Compare commits
339 Commits
Author | SHA1 | Date |
---|---|---|
teddit | 4536a7f460 | |
artemislena | 4b2c1c4784 | |
teddit | ebb1b46af3 | |
teddit | 8194c065c9 | |
lostskunk_Donetsk | 227591acff | |
lostskunk_Donetsk | 0f4c5030cd | |
teddit | 5997517825 | |
sneednet | 59abc28178 | |
sneednet | 3f5acf0fce | |
teddit | 78973f2562 | |
teddit | a5b4bedfaa | |
x4 | 2bb2efaca9 | |
teddit | 5ad837373a | |
teddit | 242deb4e05 | |
teddit | 2f3e820fb4 | |
cypherhades | baa4fbd44e | |
ConcordOne | 8d800e490c | |
teddit | b0ce6c52a6 | |
teddit | e6ae8bf0c3 | |
teddit | 490556fc6a | |
No-Logs.com | d05ecf2af6 | |
No-Logs.com | 04980be0d0 | |
teddit | 0536dcd505 | |
Kyle David Rohland | ec882c6869 | |
Kyle David Rohland | 28bd75bdb5 | |
No-Logs.com | 6a2641664f | |
teddit | 50b112bfbc | |
teddit | a4558ce3ea | |
teddit | 6d8f27a09a | |
ppsn | 605e9064a1 | |
teddit | d574b42297 | |
No-Logs.com | 1fb2d45b06 | |
zaggynl | e6ccc292b5 | |
ppsn | 13e7a13c87 | |
ppsn | 76c57cc6aa | |
teddit | f73b9c2bea | |
ppsn | 809402937d | |
ppsn | 844b1d2056 | |
ppsn | f56ec2fb2f | |
ppsn | 8e5f270783 | |
teddit | a23e606bee | |
teddit | 5c147d0d82 | |
teddit | b9f108f675 | |
teddit | dbbb1ac6f7 | |
ppsn | 2ac1466231 | |
HexagonCDN | 298982dfff | |
Wibi | a02025a86f | |
teddit | 96a55fb2ce | |
teddit | 21ddd3b89f | |
teddit | 25e789fdad | |
teddit | 68aed7b9be | |
teddit | 9cb6a80c15 | |
teddit | 8c52544404 | |
teddit | 563be382d3 | |
The1029 | 596e8ef093 | |
Anshuman Kumar | 0969d694db | |
Anshuman Kumar | aa75cc239a | |
teddit | 079ea36d24 | |
teddit | d31c418816 | |
teddit | d11ddce9d2 | |
teddit | 572068aca4 | |
teddit | ea6ad7c8ec | |
Anshuman Kumar | ed0c0c7d28 | |
Anshuman Kumar | 9a328612c4 | |
dependabot[bot] | e28ddf2935 | |
Anshuman Kumar | b3b1cbbc95 | |
Anshuman Kumar | b6acf7542a | |
Anshuman Kumar | 2873e2aea5 | |
Anshuman Kumar | ab95c341c6 | |
Anshuman Kumar | f7f2d0beec | |
dependabot[bot] | f7cecfd465 | |
Anshuman Kumar | df20a9c7fe | |
dependabot[bot] | 0ea8b831c3 | |
dependabot[bot] | 625c86a2b2 | |
dependabot[bot] | a9c8f6b6ce | |
Anshuman Kumar | c71bf6ee48 | |
bradmurray | d96372b08a | |
NunoSempere | e59e57ca83 | |
NunoSempere | 494c7f5417 | |
CosmosDev | 2c5c9d7cde | |
CosmosDev | 54c658ff9b | |
CosmosDev | 3a51e9d165 | |
CosmosDev | baddb1aec2 | |
CosmosDev | eec2a24eb3 | |
CosmosDev | 0852396b6d | |
teddit | 22b63a3415 | |
Jean-Luc Tibaux | 50c369833b | |
Jean-Luc Tibaux | 45dc798eef | |
teddit | e2237f1b93 | |
teddit | ee7068a88c | |
kazuki | dc58122aa1 | |
kazuki | ba207e18c7 | |
kazuki | 4241490793 | |
Jean-Luc Tibaux | d70e6a4265 | |
teddit | bb06a47b1a | |
ltGuillaume | eb2131c2ff | |
teddit | 4c3c743536 | |
teddit | 66b11dc647 | |
Hygna | 83a8c48d9c | |
valere | ba3230be1a | |
valere | 0003bdcbb8 | |
teddit | 6fa109e6ff | |
teddit | a4b130af81 | |
teddit | 1ece7467dc | |
alan | bc3af7b609 | |
Austin Huang | 0cf3d6d6c9 | |
NunoSempere | 718d04c412 | |
NunoSempere | dcdfc28e00 | |
teddit | 27874a6766 | |
teddit | e5640ef5a3 | |
teddit | facab379ca | |
apmechev | e5d374f5f8 | |
Hygna | ba8ed2acb0 | |
teddit | ccfdff679e | |
Wibi | b66e4159d2 | |
Wibi | 738a7ba646 | |
teddit | 48b89a7a8c | |
teddit | 52bc1f4945 | |
teddit | 55b17e5141 | |
teddit | 90f0872d77 | |
artemislena | bccae3cce5 | |
artemislena | e5cc5c8d3b | |
teddit | 67b746c4df | |
technonerd | e120ecfca2 | |
technonerd | c515f351be | |
teddit | d85f0680ad | |
Moxie "The Cobra" Widulski | dbe25af3ac | |
Moxie "The Cobra" Widulski | e697729466 | |
teddit | cee89787ea | |
PrivacyTools | 163bfe8e4d | |
PrivacyTools | 09ac20dd6b | |
teddit | 07984ab36b | |
ConcordOne | baba8b7fab | |
ConcordOne | 0da38c783a | |
teddit | cbd0babf43 | |
teddit | 25fa819833 | |
dr460nf1r3 | 372f21328f | |
teddit | 5f1d50bc8c | |
apmechev | 18b26aa758 | |
teddit | 7ef04def16 | |
Abdelkarim Djelalda | f7082acc41 | |
Abdelkarim Djelalda | f33d78f6a4 | |
teddit | 74625f39b7 | |
teddit | 799bc837c7 | |
teddit | 07050c9cf6 | |
teddit | 2b22ffa105 | |
teddit | 02fd92ce2c | |
teddit | 8af3ec3591 | |
triallax | e29b41a728 | |
teddit | e3b2c663d9 | |
teddit | 842a7ca802 | |
teddit | 0863c841e4 | |
teddit | 84d0009984 | |
teddit | a0c74aa309 | |
teddit | 4663b3a78d | |
redmt | 4ff7152be1 | |
teddit | b1f65f31d8 | |
StevenNMeza | 231348e75e | |
teddit | 1fbef42a7c | |
redmt | 9fd891b474 | |
redmt | 0bf27cfd6c | |
redmt | fc56f0a833 | |
teddit | 1759724268 | |
teddit | 601e393dda | |
redmt | d8edffba1a | |
teddit | 270e9e5ceb | |
teddit | 28c3c60078 | |
teddit | 7f981f69ae | |
redmt | 1f6f5d621d | |
redmt | 53a5766de7 | |
redmt | a0fcdf101e | |
redmt | 55bd044b06 | |
redmt | b2dba3f723 | |
redmt | 8f57cb143b | |
redmt | 69a9b0e080 | |
redmt | afbad4ae3b | |
redmt | 20db540b5c | |
redmt | cfdfd4a2b1 | |
redmt | 555ff9068b | |
redmt | 2ff979bdda | |
redmt | 108f87a5e4 | |
teddit | b0d5377e21 | |
teddit | 0432c7484d | |
teddit | a63b5beb7e | |
teddit | 60d9b33825 | |
teddit | c9b2dbf750 | |
teddit | b797cef167 | |
teddit | 096c7218d4 | |
redmt | fb6673265e | |
redmt | 546fdb5d77 | |
redmt | d368acac29 | |
redmt | d6b2e0700a | |
redmt | 6c52664155 | |
redmt | 27ade36805 | |
redmt | 354180119f | |
teddit | 3855a618ee | |
teddit | 9e4ea80c7e | |
teddit | 1c9b125b70 | |
redmt | 7f8cc27ffb | |
redmt | 7a508c55ee | |
redmt | 05d7db481c | |
redmt | ae429bcbf9 | |
redmt | a73bd2e3ec | |
redmt | 9c8e72eccd | |
redmt | 0bf3ead82d | |
redmt | cc6c2a1cd6 | |
redmt | 6328e41bcf | |
redmt | 319fa35d5f | |
redmt | 064c97579e | |
redmt | 811348c1af | |
redmt | 2f51368ac6 | |
redmt | 932d7f07ee | |
redmt | 5ef61af67f | |
redmt | 04395734cf | |
redmt | 2a92f0a57d | |
redmt | 12790f7e8e | |
redmt | 22328e318c | |
redmt | 7ceb0e8b5d | |
redmt | 9553b94cc0 | |
teddit | 8ccc694d2f | |
teddit | e640e794db | |
teddit | 3612345fab | |
teddit | 1b6e1e5494 | |
teddit | 77917c8ea5 | |
analogue | 9b6dec1108 | |
analogue | 4bb02eaf03 | |
teddit | 09ca31701a | |
teddit | 925fe0565e | |
teddit | 86dab3b816 | |
triallax | 87bd0138c1 | |
Sam Therapy | 4626a0f9bf | |
analogue | ee7508b24a | |
teddit | a53a9fc3df | |
teddit | 5c8cbc8595 | |
triallax | 2b03532289 | |
StevenNMeza | a89ab7d1b5 | |
teddit | 2d69623bf1 | |
TheFrenchGhosty | 1baa654a54 | |
teddit | fa8f0ba02b | |
teddit | 8bcbe8d4ee | |
teddit | 6c84bdd1e3 | |
teddit | d71c88871c | |
sartateme | 274a8be24e | |
teddit | 3ef2f004ea | |
amrw | 063523ed4d | |
teddit | 7c7709e74f | |
teddit | eac2627114 | |
teddit | 265c33fcd2 | |
teddit | 01c41c7adf | |
teddit | 397a02c821 | |
teddit | 3ad64d5c87 | |
teddit | d315051a7b | |
teddit | d947182058 | |
teddit | e87b811883 | |
teddit | 446f388be2 | |
teddit | 791a80b337 | |
teddit | 301774ce8d | |
Austin Huang | 08437d8663 | |
Austin Huang | b5878ea031 | |
Austin Huang | c97fb5a517 | |
teddit | 1efe34c0ad | |
teddit | 7a9603f850 | |
teddit | 15256b1cd8 | |
teddit | bc274e9660 | |
teddit | ab44566561 | |
teddit | a411df0503 | |
Jean-Luc Tibaux | 849475925d | |
Jean-Luc Tibaux | dd45b2633a | |
nfusionz | fcc0fce890 | |
nfusionz | c1faeeb05c | |
teddit | 734ac6a817 | |
gawii0 | 2e030e2c4b | |
teddit | 010c934d60 | |
teddit | ab076d020f | |
gawii0 | 0d2de61444 | |
gawii0 | e870b9ea50 | |
gawii0 | e0bf08132d | |
gawii0 | aa3a854b6e | |
teddit | 8315ad3f16 | |
teddit | 4bf092e481 | |
TheFrenchGhosty | cadf67f488 | |
teddit | 992429818f | |
dominion | 2ea766e01a | |
dominion | fd3d96a8d3 | |
teddit | be28d7fdfa | |
TotalDarkness | 168d896e69 | |
teddit | 126eb5d0cc | |
Ming Di Leom | 0cf6a2228f | |
teddit | b476f9f2b6 | |
teddit | 0eb5ce1b6e | |
teddit | c9637524ec | |
teddit | 9783091216 | |
teddit | 08e9f90233 | |
teddit | 30d0000dca | |
teddit | d895e400ef | |
3nprob | 8bf7d4f792 | |
3nprob | 56a2f6b266 | |
teddit | 660e5681be | |
sethforprivacy | 631b63c6eb | |
teddit | 59bacc0fde | |
tacerus | a37d20f889 | |
teddit | f8e6d326ba | |
teddit | 998fa01a39 | |
TheFrenchGhosty | adf8258670 | |
TheFrenchGhosty | db63adcb7d | |
TheFrenchGhosty | 43f846c1e5 | |
TheFrenchGhosty | eb8e1f394b | |
teddit | 692d6164b3 | |
teddit | c34c32cc35 | |
teddit | a9f13741bb | |
teddit | 5a01338428 | |
teddit | c4d167c787 | |
teddit | d475407061 | |
teddit | 9d01c544d1 | |
arche_dev | d2feeac288 | |
teddit | 8bb949b2b3 | |
teddit | 9e515c4985 | |
teddit | 0707349a85 | |
teddit | cc9d9e5579 | |
teddit | 873e56a23b | |
teddit | a6b9599463 | |
teddit | 813fb3566c | |
teddit | 4cc8dd7bd5 | |
json | e1df2ea8ae | |
json | 6ced924bc8 | |
json | 6ff892767c | |
json | 153a50e60a | |
json | 0bf3e36c56 | |
json | 9bc3ff8d34 | |
json | 711f2450c7 | |
json | aae3e00ab1 | |
json | 1c7a3a8f5a | |
json | 5f5388da6f | |
json | d95642cf80 | |
json | 93f70533aa | |
json | f3cc837a01 | |
json | d1ef359435 | |
json | 7f347d13f7 | |
teddit | 6433afde09 |
|
@ -5,3 +5,9 @@ updates:
|
|||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Maintain dependencies for npm
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
|
@ -10,26 +10,26 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: "Checkout repository"
|
||||
uses: "actions/checkout@v2"
|
||||
uses: "actions/checkout@v3"
|
||||
-
|
||||
name: Build and push to Docker Hub and Github Packages Docker Registry
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
|
|
|
@ -9,26 +9,26 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: "Checkout repository"
|
||||
uses: "actions/checkout@v2"
|
||||
uses: "actions/checkout@v3"
|
||||
-
|
||||
name: Build and push to Docker Hub and Github Packages Docker Registry
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
node_modules/
|
||||
*.log
|
||||
config.js
|
||||
.vscode/
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"singleQuote": true
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
# Use LTS Node.js base image
|
||||
FROM node:14.17-alpine
|
||||
# Use LTS Node.js slim image
|
||||
FROM node:slim
|
||||
|
||||
# Video support dependency
|
||||
RUN apk add ffmpeg
|
||||
RUN apt-get update && apt-get install -y ffmpeg wget
|
||||
|
||||
# Install NPM dependencies and copy the project
|
||||
WORKDIR /teddit
|
||||
|
@ -12,4 +12,6 @@ COPY config.js.template ./config.js
|
|||
|
||||
RUN find ./static/ -type d -exec chmod -R 777 {} \;
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
CMD npm start
|
||||
|
|
140
README.md
140
README.md
|
@ -1,5 +1,14 @@
|
|||
# teddit
|
||||
|
||||
## teddit is no more actively maintained!
|
||||
|
||||
[Due to Reddit's API changes](https://en.wikipedia.org/wiki/2023_Reddit_API_controversy), this project is no more actively maintained.
|
||||
Feel free to fork the project if you like, or contribute to other alternative Reddit front-ends, such as Libreddit, which are trying to come up with circumventions.
|
||||
|
||||
This project is still maintained, but just not actively. You can create PRs, but don't expect them to be merged right away.
|
||||
|
||||
---
|
||||
|
||||
[teddit.net](https://teddit.net)
|
||||
|
||||
A free and open source alternative Reddit front-end focused on privacy.
|
||||
|
@ -22,21 +31,37 @@ XMR: 832ogRwuoSs2JGYg7wJTqshidK7dErgNdfpenQ9dzMghNXQTJRby1xGbqC3gW3GAifRM9E84J91
|
|||
|
||||
Community instances:
|
||||
|
||||
| Instance | Onion Link | Notes |
|
||||
|-|-|-|
|
||||
| [teddit.ggc-project.de](https://teddit.ggc-project.de) | | |
|
||||
| [teddit.kavin.rocks](https://teddit.kavin.rocks) | [teddit4w6cmzmj5kimhfc...onion](http://teddit4w6cmzmj5kimhfcavs7yo5s7alszvsi2khqutqtlaanpcftfyd.onion/) | |
|
||||
| [teddit.zaggy.nl](https://teddit.zaggy.nl) | | |
|
||||
| [teddit.namazso.eu](https://teddit.namazso.eu) | | |
|
||||
| [teddit.nautolan.racing](https://teddit.nautolan.racing) | | |
|
||||
| [teddit.tinfoil-hat.net](https://teddit.tinfoil-hat.net) | | |
|
||||
| [teddit.domain.glass](https://teddit.domain.glass) | | |
|
||||
| [snoo.ioens.is](https://snoo.ioens.is) | [snoo.ioensistjs7wd746...onion](http://snoo.ioensistjs7wd746zluwixvojbbkxhr37lepdvwtdfeav673o64iflqd.onion/) | |
|
||||
| [teddit.httpjames.space](https://teddit.httpjames.space) | | |
|
||||
| [ibarajztopxnuhabfu7f...onion](http://ibarajztopxnuhabfu7fg6gbudynxofbnmvis3ltj6lfx47b6fhrd5qd.onion) | | |
|
||||
| [xugoqcf2pftm76vbznx4...i2p](http://xugoqcf2pftm76vbznx4xuhrzyb5b6zwpizpnw2hysexjdn5l2tq.b32.i2p) | | |
|
||||
| [teddit.alefvanoon.xyz](https://teddit.alefvanoon.xyz) | | |
|
||||
| [incogsnoo.com](https://incogsnoo.com) | [tedditfyn6idalzso5wam....onion](tedditfyn6idalzso5wam5qd3kdtxoljjhbrbbx34q2xkcisvshuytad.onion/) | I2P: [http://teddit.i2p](http://teddit.i2p) |
|
||||
| Instance | Onion Link | I2P | Notes |
|
||||
|-|-|-|-|
|
||||
| [teddit.ggc-project.de](https://teddit.ggc-project.de) | | | |
|
||||
| [teddit.zaggy.nl](https://teddit.zaggy.nl) | | | |
|
||||
| [teddit.tinfoil-hat.net](https://teddit.tinfoil-hat.net) | | | |
|
||||
| [teddit.domain.glass](https://teddit.domain.glass) | | | |
|
||||
| [snoo.ioens.is](https://snoo.ioens.is) | [snoo.ioensistjs7wd746...onion](http://snoo.ioensistjs7wd746zluwixvojbbkxhr37lepdvwtdfeav673o64iflqd.onion/) | | |
|
||||
| [teddit.httpjames.space](https://teddit.httpjames.space) | | | |
|
||||
| [teddit.xbdm.fun](https://teddit.xbdm.fun) | | | |
|
||||
| | [ibarajztopxnuhabfu7f...onion](http://ibarajztopxnuhabfu7fg6gbudynxofbnmvis3ltj6lfx47b6fhrd5qd.onion) | [xugoqcf2pftm76vbznx4...i2p](http://xugoqcf2pftm76vbznx4xuhrzyb5b6zwpizpnw2hysexjdn5l2tq.b32.i2p) | Operated by [mdleom.com](https://mdleom.com/about/#Services) |
|
||||
| [incogsnoo.com](https://incogsnoo.com) | [tedditfyn6idalzso5wam....onion](http://tedditfyn6idalzso5wam5qd3kdtxoljjhbrbbx34q2xkcisvshuytad.onion/) | [http://teddit.i2p](http://teddit.i2p) | |
|
||||
| [teddit.pussthecat.org](https://teddit.pussthecat.org) | | | Operated by [PussTheCat.org](https://pussthecat.org/) |
|
||||
| [reddit.lol](https://reddit.lol) | [http://dawtyi5e2cfyfmoht...onion](http://dawtyi5e2cfyfmoht4izmczi42aa2zwh6wi34zwvc6rzf2acpxhrcrad.onion) | [http://vzeiwzi7ogwl3i...b32.i2p](http://vzeiwzi7ogwl3ijrfek4fbtwhvamxcpyqoc3s4vcgnhlp54s5clq.b32.i2p) | Operated by https://liberta.casa | |
|
||||
| [teddit.sethforprivacy.com](https://teddit.sethforprivacy.com/) | [qtpvyiaqhmwccx...onion/](http://qtpvyiaqhmwccxwzsqubd23xhmmrt75tdyw35kp43w4hvamsgl3x27ad.onion/) | | For more similar hosted tools, see [blog.sethforprivacy.com](https://blog.sethforprivacy.com/about/#my-community-resources) |
|
||||
| [teddit.adminforge.de](https://teddit.adminforge.de) | | | Operated by https://adminforge.de |
|
||||
| [teddit.bus-hit.me](https://teddit.bus-hit.me) | | | Operated by https://bus-hit.me |
|
||||
| [teddit.froth.zone](https://teddit.froth.zone) | | | |
|
||||
| [rdt.trom.tf](https://rdt.trom.tf) | | | Part of the https://trom.tf project |
|
||||
| [teddit.encrypted-data.xyz](https://teddit.encrypted-data.xyz) | | | |
|
||||
| [i.opnxng.com](https://i.opnxng.com) | | | |
|
||||
| [teddit.tokhmi.xyz](https://teddit.tokhmi.xyz) | | | |
|
||||
| [teddit.garudalinux.org](https://teddit.garudalinux.org) | | | Managed by https://garudalinux.org |
|
||||
| [teddit.privacytools.io](https://teddit.privacytools.io) | [jnuonmf2n36sfdmyksqq....onion](http://jnuonmf2n36sfdmyksqqqyab3w63cq4kx24olyjleh5z6zzfvyt7uqqd.onion) | | Part of [PrivacyTools.io](https://www.privacytools.io/) and hosted by [Privex](https://www.privex.io/) |
|
||||
| [td.vern.cc](https://td.vern.cc) | [td.vernccvbvyi5qhfzyqen...onion](http://td.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion) | [td.vern.i2p](http://verncco2oaxjikammz4pi7umzp673cme6zuemx7yeeewspwrw3va.b32.i2p) | Operated by https://vern.cc |
|
||||
| [teddit.rawbit.ninja](https://teddit.rawbit.ninja) | [yqu4yj5lju7bmlwpzpml...onion](http://yqu4yj5lju7bmlwpzpmltb5gsu6cw7nnbcxxx4iqemwa56nxjiggf4qd.onion) | | Operated by https://rawbit.ninja |
|
||||
| [teddit.hostux.net](https://teddit.hostux.net) | | | Operated by https://hostux.net |
|
||||
| [teddit.no-logs.com](https://teddit.no-logs.com/) | | | Operated by https://no-logs.com |
|
||||
| [teddit.projectsegfau.lt](https://teddit.projectsegfau.lt) | [teddit.pjsfkvpxlinjamta...onion](http://teddit.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion) | | Maintained by Project Segfault Team (https://projectsegfau.lt/team) |
|
||||
| [teddit.laserdisc.tokyo](https://teddit.laserdisc.tokyo) | | | |
|
||||
| [t.sneed.network](https://t.sneed.network) | [t.sneed4fmhevap3ci4x...onion](http://t.sneed4fmhevap3ci4xhf4wgkf72lwk275lcgomnfgwniwmqvaxyluuid.onion/) | | Operated by [sneed.network](https://sneed.network) |
|
||||
| | [teddit.skunky7dhv7no...onion](http://teddit.skunky7dhv7nohsoalpwe3sxfz3fbkad7r3wk632riye25vqm3meqead.onion/) | | Self-hosted, works only from 7-11 AM Moscow time to 10-12 PM, in Donetsk |
|
||||
|
||||
<!--
|
||||
Remove the Changelog section, because the CHANGELOG.md is not updated anymore
|
||||
|
@ -47,9 +72,55 @@ See ```CHANGELOG.md```
|
|||
|
||||
## Installation
|
||||
|
||||
### Docker-compose method
|
||||
### Docker-compose method (production)
|
||||
|
||||
```console
|
||||
```docker
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
|
||||
teddit:
|
||||
container_name: teddit
|
||||
image: teddit/teddit:latest
|
||||
environment:
|
||||
- DOMAIN=teddit.net
|
||||
- USE_HELMET=true
|
||||
- USE_HELMET_HSTS=true
|
||||
- TRUST_PROXY=true
|
||||
- REDIS_HOST=teddit-redis
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
networks:
|
||||
- teddit_net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget" ,"--no-verbose", "--tries=1", "--spider", "http://localhost:8080/about"]
|
||||
interval: 1m
|
||||
timeout: 3s
|
||||
depends_on:
|
||||
- teddit-redis
|
||||
|
||||
teddit-redis:
|
||||
container_name: teddit-redis
|
||||
image: redis:6.2.5-alpine
|
||||
command: redis-server
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=master
|
||||
networks:
|
||||
- teddit_net
|
||||
|
||||
networks:
|
||||
teddit_net:
|
||||
```
|
||||
|
||||
Note: This compose is made for a true "production" setup, and is made to be used to have teddit behind a reverse proxy, if you don't want that and prefer to directly access teddit via its port:
|
||||
|
||||
- Change `ports: - "127.0.0.1:8080:8080"` to `ports: - "8080:8080"`
|
||||
- Remove `DOMAIN=teddit.net`, `USE_HELMET=true`, `USE_HELMET_HSTS=true`, `TRUST_PROXY=true`
|
||||
|
||||
|
||||
### Docker-compose method (development)
|
||||
|
||||
```bash
|
||||
git clone https://codeberg.org/teddit/teddit
|
||||
cd teddit
|
||||
docker-compose build
|
||||
|
@ -73,6 +144,7 @@ The following variables may be set to customize your deployment at runtime.
|
|||
| flairs_enabled | Enables the rendering of user and link flairs on Teddit. Defaults to **true** |
|
||||
| highlight_controversial | Enables controversial comments to be indicated by a typographical dagger (†). Defaults to **true** |
|
||||
| api_enabled | Teddit API feature. Might increase loads significantly on your instance. Defaults to **true** |
|
||||
| api_force_https | Force HTTPS to Teddit API permalinks (see #285). Defaults to **false** |
|
||||
| video_enabled | Enables video playback within Teddit. Defaults to **true** |
|
||||
| redis_enabled | Enables Redis caching. If disabled, does not allow for any caching of Reddit API calls. Defaults to **true** |
|
||||
| redis_db | Sets the redis DB name, if required |
|
||||
|
@ -97,9 +169,9 @@ The following variables may be set to customize your deployment at runtime.
|
|||
| post_comments_sort | Defines default sort preference. Options are *confidence* (default sorting option in Reddit), *top*, *new*, *controversal*, *old*, *random*, *qa*, *live*. Defaults to **confidence** |
|
||||
| reddit_app_id | If "use_reddit_oauth" config key is set to true, you have to obtain your Reddit app ID. For testing purposes it's okay to use this project's default app ID. Create your Reddit app here: https://old.reddit.com/prefs/apps/. Make sure to create an "installed app" type of app. Default is **ABfYqdDc9qPh1w** |
|
||||
| domain_replacements | Replacements for domains in outgoing links. Tuples with regular expressions to match, and replacement values. This is in addition to user-level configuration of privacyDomains. Defaults to **[]** |
|
||||
| cache_control | *Boolean* If true, teddit will automatically try to keep the size of the cache directory under ```config.cache_max_size```. Defaults to **true** |
|
||||
| cache_max_size | In Megabytes (MB), how much can we cache media files to the disk? Default is 3000 MB (~3 GB). Note: This is not perfectly exact limit. Defaults to **3000** |
|
||||
| cache_control_interval | How often the size of the cache directory is checked. Default is every 30 minutes. Defaults to **1000 * 60 * 30** |
|
||||
| cache_control | *Boolean* If true, teddit will automatically remove all cached static files. Defaults to **true** |
|
||||
| cache_control_interval | How often the cache directory for static files is emptied (in hours). Default is every 24 hours. Requires cache_control to be true. Defaults to **24** |
|
||||
| suggested_subreddits | Array of suggested subreddits, which are displayed in the top bar (if the user doesn't have any subscriptions) and in the cleaned home page. Defaults to Reddit's default suggested subreddits. |
|
||||
|
||||
### Manual
|
||||
|
||||
|
@ -107,13 +179,13 @@ The following variables may be set to customize your deployment at runtime.
|
|||
|
||||
1. (Optional) Install [redis-server](https://redis.io).
|
||||
|
||||
Highly recommended – it works as a cache for Reddit API calls.
|
||||
Highly recommended – it works as a cache for Reddit API calls.
|
||||
|
||||
1. (Optional) Install [ffmpeg](https://ffmpeg.org).
|
||||
|
||||
It's needed if you want to support videos.
|
||||
|
||||
```console
|
||||
```bash
|
||||
# Linux
|
||||
apt install redis-server ffmpeg
|
||||
|
||||
|
@ -123,7 +195,7 @@ The following variables may be set to customize your deployment at runtime.
|
|||
|
||||
1. Clone and set up the repository.
|
||||
|
||||
```console
|
||||
```bash
|
||||
git clone https://codeberg.org/teddit/teddit
|
||||
cd teddit
|
||||
npm install --no-optional
|
||||
|
@ -133,3 +205,25 @@ The following variables may be set to customize your deployment at runtime.
|
|||
```
|
||||
|
||||
Teddit should now be running at <http://localhost:8080>.
|
||||
|
||||
You can also run teddit from a process manager like [pm2](https://www.npmjs.com/package/pm2):
|
||||
|
||||
```
|
||||
## To run:
|
||||
npm install pm2 -g
|
||||
pm2 start app.js --name teddit
|
||||
|
||||
## To run on startup:
|
||||
pm2 startup
|
||||
pm2 save ## if using systemd, see below.
|
||||
|
||||
## To restart or stop
|
||||
pm2 restart teddit
|
||||
pm2 stop teddit
|
||||
```
|
||||
|
||||
See also the [pm2 instructions for running a project on startup](https://pm2.keymetrics.io/docs/usage/startup/). In particular, if using systemd, see the section on how to modify the systemd init file so that it runs after your system connects to the network.
|
||||
|
||||
## Legal
|
||||
|
||||
Teddit does not host any content. All content shown on any Teddit instances is from Reddit™. Reddit is a trademark of Reddit Inc. Teddit is not affiliated with Reddit Inc. Any issues with content shown on any Teddit instances need to be reported to Reddit, not the instance host's internet provider or domain provider.
|
||||
|
|
58
app.js
58
app.js
|
@ -12,41 +12,7 @@ const pug = require('pug');
|
|||
const compression = require('compression');
|
||||
const express = require('express');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const r = require('redis');
|
||||
|
||||
const redis = (() => {
|
||||
if (!config.redis_enabled) {
|
||||
// Stub Redis if disabled
|
||||
return {
|
||||
get: (_, callback) => callback(null, null),
|
||||
setex: (_, _1, _2, callback) => callback(null),
|
||||
on: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
const redisOptions = {
|
||||
host: '127.0.0.1',
|
||||
port: 6379,
|
||||
};
|
||||
|
||||
if (config.redis_db) {
|
||||
redisOptions.db = config.redis_db;
|
||||
}
|
||||
|
||||
if (config.redis_host) {
|
||||
redisOptions.host = config.redis_host;
|
||||
}
|
||||
|
||||
if (config.redis_port && config.redis_port > 0) {
|
||||
redisOptions.port = config.redis_port;
|
||||
}
|
||||
|
||||
if (config.redis_password) {
|
||||
redisOptions.password = config.redis_password;
|
||||
}
|
||||
|
||||
return r.createClient(redisOptions);
|
||||
})();
|
||||
const { redis } = require('./inc/redis');
|
||||
|
||||
const nodeFetch = require('node-fetch');
|
||||
const fetch = config.http_proxy
|
||||
|
@ -83,7 +49,7 @@ let https = null;
|
|||
if (config.https_enabled) {
|
||||
const privateKey = fs.readFileSync(`${config.cert_dir}/privkey.pem`, 'utf8');
|
||||
const certificate = fs.readFileSync(`${config.cert_dir}/cert.pem`, 'utf8');
|
||||
const ca = fs.readFileSync(`${config.cert_dir}/chain.pem`, 'utf8');
|
||||
const ca = fs.readFileSync(`${config.cert_dir}/fullchain.pem`, 'utf8');
|
||||
const credentials = {
|
||||
key: privateKey,
|
||||
cert: certificate,
|
||||
|
@ -140,6 +106,13 @@ app.use(express.static(`${__dirname}/static`));
|
|||
app.set('views', './views');
|
||||
app.set('view engine', 'pug');
|
||||
|
||||
if (config.redirect_http_to_https) {
|
||||
app.use((req, res, next) => {
|
||||
if (req.secure) next();
|
||||
else res.redirect(`https://${req.headers.host}${req.url}`);
|
||||
});
|
||||
}
|
||||
|
||||
const redditAPI = require('./inc/initRedditApi.js')(fetch);
|
||||
|
||||
/*
|
||||
|
@ -155,19 +128,6 @@ app.use('/', allRoutes);
|
|||
// The old routes
|
||||
//require('./routes')(app, redis, fetch, redditAPI);
|
||||
|
||||
if (config.redirect_http_to_https) {
|
||||
app.use((req, res, next) => {
|
||||
if (req.secure) next();
|
||||
else res.redirect(`https://${req.headers.host}${req.url}`);
|
||||
});
|
||||
}
|
||||
|
||||
redis.on('error', (error) => {
|
||||
if (error) {
|
||||
console.error(`Redis error: ${error}`);
|
||||
}
|
||||
});
|
||||
|
||||
const cacheControl = require('./cacheControl.js');
|
||||
cacheControl.removeCacheFiles();
|
||||
|
||||
|
|
|
@ -1,66 +1,32 @@
|
|||
module.exports.removeCacheFiles = function() {
|
||||
const fs = require('fs')
|
||||
const config = require('./config')
|
||||
const pics = './static/pics'
|
||||
const flairs = './static/pics/flairs'
|
||||
const icons = './static/pics/icons'
|
||||
const thumbs = './static/pics/thumbs'
|
||||
const vids = './static/vids'
|
||||
let util = require('util')
|
||||
let spawn = require('child_process').spawn
|
||||
const config = require('./config');
|
||||
|
||||
let usage
|
||||
const limit = config.cache_max_size
|
||||
async function deleteStatic() {
|
||||
const fs = require('fs');
|
||||
const pics = './static/pics/';
|
||||
const vids = './static/vids/';
|
||||
|
||||
function getUsage() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let size = spawn('du', ['-sBM', './static/'])
|
||||
size.stdout.on('data', function (data) {
|
||||
data = data.toString()
|
||||
let lines = data.split('\n')
|
||||
if(lines) {
|
||||
for(let i = lines.length; i >= 0; i--) {
|
||||
if(lines[i] && lines[i].includes('./static/')) {
|
||||
usage = parseInt(lines[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve(usage)
|
||||
})
|
||||
})
|
||||
fs.rmdir(pics, { recursive: true, force: true }, () => {
|
||||
fs.rmdir(vids, { recursive: true, force: true }, () => {
|
||||
['pics/thumbs', 'pics/flairs', 'pics/icons', 'vids'].map((d) => `./static/${d}`)
|
||||
.filter((d) => !fs.existsSync(d))
|
||||
.forEach((d) => fs.mkdirSync(d, { recursive: true }));
|
||||
|
||||
console.log('Cleared cached static media files. You can turn this off by setting the config.cache_control to false.');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFiles() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
usage = await getUsage()
|
||||
if(usage > limit) {
|
||||
const { exec } = require('child_process')
|
||||
exec(`cd ${pics} && ls -1btr -Iflairs -Iicons -Ithumbs -I.gitignore | head -50 | xargs rm -f --`)
|
||||
exec(`cd ${flairs} && ls -1btr -I.gitignore | head -6 | xargs rm -f --`)
|
||||
exec(`cd ${icons} && ls -1btr -I.gitignore | head -6 | xargs rm -f --`)
|
||||
exec(`cd ${thumbs} && ls -1btr -I.gitignore | head -80 | xargs rm -f --`)
|
||||
exec(`cd ${vids} && ls -1btr -I.gitignore | head -2 | xargs rm -f --`)
|
||||
}
|
||||
resolve(1)
|
||||
})
|
||||
if(config.cache_control) {
|
||||
deleteStatic();
|
||||
|
||||
let hours = config.cache_control_interval;
|
||||
if (hours < 1 || hours > 10000 || isNaN(hours)) {
|
||||
hours = 24;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
usage = await getUsage()
|
||||
if(usage > limit) {
|
||||
console.log('Started removeCacheFiles()')
|
||||
while(usage > limit) {
|
||||
await deleteFiles()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(config.cache_control) {
|
||||
main()
|
||||
|
||||
const interval_ms = config.cache_control_interval
|
||||
setInterval(() => {
|
||||
main()
|
||||
}, interval_ms)
|
||||
deleteStatic();
|
||||
}, 1000 * 60 * 60 * hours);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,13 @@ const config = {
|
|||
use_reddit_oauth: process.env.USE_REDDIT_OAUTH === 'true' || false, // If false, teddit uses Reddit's public API. If true, you need to have your own Reddit app ID (enter the app ID to the "reddit_app_id" config key).
|
||||
cert_dir: process.env.CERT_DIR || '', // For example '/home/teddit/letsencrypt/live/teddit.net', if you are using https. No trailing slash.
|
||||
theme: process.env.THEME || 'auto', // One of: 'dark', 'sepia', 'auto', ''. Auto theme uses browser's theme detection (Dark or White theme). White theme is set by the empty the option ('').
|
||||
flairs_enabled: process.env.FLAIRS_ENABLED !== 'true' || true, // Enables the rendering of user and link flairs on teddit
|
||||
highlight_controversial: process.env.HIGHLIGHT_CONTROVERSIAL !== 'true' || true, // Enables controversial comments to be indicated by a typographical dagger (†)
|
||||
api_enabled: process.env.API_ENABLED !== 'true' || true, // Teddit API feature. Might increase loads significantly on your instance.
|
||||
video_enabled: process.env.VIDEO_ENABLED !== 'true' || true,
|
||||
redis_enabled: process.env.REDIS_ENABLED !== 'true' || true, // If disabled, does not cache Reddit API calls
|
||||
clean_homepage: !('CLEAN_HOMEPAGE' in process.env) || process.env.CLEAN_HOMEPAGE === 'true', // Allows the clean homepage to be used (similar to invidious), instead of the usual reddit-like frontpage
|
||||
flairs_enabled: !('FLAIRS_ENABLED' in process.env) || process.env.FLAIRS_ENABLED === 'true', // Enables the rendering of user and link flairs on teddit
|
||||
highlight_controversial: !('HIGHLIGHT_CONTROVERSIAL' in process.env) || process.env.HIGHLIGHT_CONTROVERSIAL === 'true', // Enables controversial comments to be indicated by a typographical dagger (†)
|
||||
api_enabled: !('API_ENABLED' in process.env) || process.env.API_ENABLED === 'true', // Teddit API feature. Might increase loads significantly on your instance.
|
||||
api_force_https: process.env.API_FORCE_HTTPS === 'true' || false, // Force HTTPS to Teddit API permalinks (see #285).
|
||||
video_enabled: !('VIDEO_ENABLED' in process.env) || process.env.VIDEO_ENABLED === 'true',
|
||||
redis_enabled: !('REDIS_ENABLED' in process.env) || process.env.REDIS_ENABLED === 'true', // If disabled, does not cache Reddit API calls
|
||||
redis_db: process.env.REDIS_DB,
|
||||
redis_host: process.env.REDIS_HOST || '127.0.0.1',
|
||||
redis_password: process.env.REDIS_PASSWORD,
|
||||
|
@ -18,23 +20,24 @@ const config = {
|
|||
https_enabled: process.env.HTTPS_ENABLED === 'true' || false,
|
||||
redirect_http_to_https: process.env.REDIRECT_HTTP_TO_HTTPS === 'true' || false,
|
||||
redirect_www: process.env.REDIRECT_WWW === 'true' || false,
|
||||
use_compression: process.env.USE_COMPRESSION !== 'true' || true,
|
||||
use_compression: !('USE_COMPRESSION' in process.env) || process.env.USE_COMPRESSION === 'true',
|
||||
use_view_cache: process.env.USE_VIEW_CACHE === 'true' || false,
|
||||
use_helmet: process.env.USE_HELMET === 'true' || false, // Recommended to be true when using https
|
||||
use_helmet_hsts: process.env.USE_HELMET_HSTS === 'true' || false, // Recommended to be true when using https
|
||||
trust_proxy: process.env.TRUST_PROXY === 'true' || false, // Enable trust_proxy if you are using reverse proxy like nginx
|
||||
trust_proxy_address: process.env.TRUST_PROXY_ADDRESS || '127.0.0.1',
|
||||
http_proxy: process.env.HTTP_PROXY,
|
||||
nsfw_enabled: process.env.NSFW_ENABLED !== 'true' || true, // Enable NSFW (over 18) content. If false, a warning is shown to the user before opening any NSFW post. When the NFSW content is disabled, NSFW posts are hidden from subreddits and from user page feeds. Note: Users can set this to true or false from their preferences.
|
||||
videos_muted: process.env.VIDEOS_MUTED !== 'true' || true, // Automatically mute all videos in posts
|
||||
nsfw_enabled: !('NSFW_ENABLED' in process.env) || process.env.NSFW_ENABLED === 'true', // Enable NSFW (over 18) content. If false, a warning is shown to the user before opening any NSFW post. When the NFSW content is disabled, NSFW posts are hidden from subreddits and from user page feeds. Note: Users can set this to true or false from their preferences.
|
||||
videos_muted: !('VIDEOS_MUTED' in process.env) || process.env.VIDEOS_MUTED === 'true', // Automatically mute all videos in posts
|
||||
post_comments_sort: process.env.POST_COMMENTS_SORT || 'confidence', // "confidence" is the default sorting in Reddit. Must be one of: confidence, top, new, controversial, old, random, qa, live.
|
||||
reddit_app_id: process.env.REDDIT_APP_ID || 'ABfYqdDc9qPh1w', // If "use_reddit_oauth" config key is set to true, you have to obtain your Reddit app ID. For testing purposes it's okay to use this project's default app ID. Create your Reddit app here: https://old.reddit.com/prefs/apps/. Make sure to create an "installed app" type of app.
|
||||
domain_replacements: process.env.DOMAIN_REPLACEMENTS
|
||||
? (JSON.parse(process.env.DOMAIN_REPLACEMENTS).map(([p, r]) => [new RegExp(p, 'gm'), r]))
|
||||
: [], // Replacements for domains in outgoing links. Tuples with regular expressions to match, and replacement values. This is in addition to user-level configuration of privacyDomains.
|
||||
cache_control: process.env.CACHE_CONTROL !== 'true' || true, // If true, teddit will automatically try to keep the size of the cache directory (static) under config.cache_max_size. By default this is set to true.
|
||||
cache_max_size: process.env.CACHE_MAX_SIZE || 3000, // How much can we cache to the disk? Default is 3000 MB (~3 GB). Note: This is not perfectly exact limit.
|
||||
cache_control_interval: process.env.CACHE_CONTROL_INTERVAL || 1000 * 60 * 30, // How often the size of the cache directory (static/) is checked. Default is every 30 minutes.
|
||||
cache_control: !('CACHE_CONTROL' in process.env) || process.env.CACHE_CONTROL === 'true', // If true, teddit will automatically remove all cached static files. By default this is set to true.
|
||||
cache_control_interval: process.env.CACHE_CONTROL_INTERVAL || 24, // How often the cache directory for static files is emptied (in hours). Requires cache_control to be true. Default is every 24 hours.
|
||||
show_upvoted_percentage: !('SHOW_UPVOTED_PERCENTAGE' in process.env) || process.env.SHOW_UPVOTED_PERCENTAGE === 'true',
|
||||
show_upvotes: !('SHOW_UPVOTES' in process.env) || process.env.SHOW_UPVOTES === 'true', // If true, teddit will show number of upvotes in posts and points in comments.
|
||||
post_media_max_heights: {
|
||||
/**
|
||||
* Sets the max-height value for images and videos in posts.
|
||||
|
@ -70,9 +73,39 @@ const config = {
|
|||
initial_limit: 100, // This is the amount of page loads one IP address can make in one minute without getting limited.
|
||||
limit_after_limited: 30 // When an IP is limited, this is the amount of page loads the IP can make in one minute.
|
||||
},
|
||||
valid_media_domains: ['preview.redd.it', 'external-preview.redd.it', 'i.redd.it', 'v.redd.it', 'a.thumbs.redditmedia.com', 'b.thumbs.redditmedia.com', 'emoji.redditmedia.com', 'styles.redditmedia.com', 'www.redditstatic.com', 'thumbs.gfycat.com', 'i.ytimg.com'],
|
||||
valid_media_domains: process.env.VALID_MEDIA_DOMAINS
|
||||
? JSON.parse(process.env.VALID_MEDIA_DOMAINS)
|
||||
: ['preview.redd.it', 'external-preview.redd.it', 'i.redd.it', 'v.redd.it', 'a.thumbs.redditmedia.com', 'b.thumbs.redditmedia.com', 'emoji.redditmedia.com', 'styles.redditmedia.com', 'www.redditstatic.com', 'thumbs.gfycat.com', 'i.ytimg.com', 'i.imgur.com'],
|
||||
valid_embed_video_domains: ['gfycat.com', 'youtube.com'],
|
||||
reddit_api_error_text: `Seems like your instance is either blocked (e.g. due to API rate limiting), reddit is currently down, or your API key is expired and not renewd properly. This can also happen for other reasons.`
|
||||
reddit_api_error_text: `Seems like your instance is either blocked (e.g. due to API rate limiting), reddit is currently down, or your API key is expired and not renewd properly. This can also happen for other reasons.`,
|
||||
/**
|
||||
* Here you can configure the suggested subreddits which are visible in the
|
||||
* cleaned homepage, and in the top bar.
|
||||
* You should keep at least 'All', and 'Saved'.
|
||||
*
|
||||
* If you set your configs with an environment variables for example with
|
||||
* docker-compose.yml, your suggested_subreddits config could be something
|
||||
* like this (note the quotes):
|
||||
* - SUGGESTED_SUBREDDITS=["Popular", "All", "Saved", "selfhosted", "linux", "datahoarder", "Monero"]
|
||||
* or
|
||||
* - 'SUGGESTED_SUBREDDITS=["Popular", "All", "Saved", "selfhosted", "linux", "datahoarder", "Monero"]'
|
||||
*/
|
||||
suggested_subreddits: process.env.SUGGESTED_SUBREDDITS
|
||||
? JSON.parse(process.env.SUGGESTED_SUBREDDITS)
|
||||
:
|
||||
['Popular', 'All', 'Saved', 'AskReddit', 'pics', 'news',
|
||||
'worldnews', 'funny', 'tifu', 'videos', 'gaming', 'aww',
|
||||
'todayilearned', 'gifs', 'Art', 'explainlikeimfive',
|
||||
'movies', 'Jokes', 'TwoXChromosomes',
|
||||
'mildlyinteresting', 'LifeProTips', 'askscience',
|
||||
'IAmA', 'dataisbeautiful', 'books', 'science',
|
||||
'Showerthoughts', 'gadgets', 'Futurology',
|
||||
'nottheonion', 'history', 'sports', 'OldSchoolCool',
|
||||
'GetMotivated', 'DIY', 'photoshopbattles', 'nosleep',
|
||||
'Music', 'space', 'food', 'UpliftingNews', 'EarthPorn',
|
||||
'Documentaries', 'InternetIsBeautiful',
|
||||
'WritingPrompts', 'creepy', 'philosophy',
|
||||
'announcements', 'listentothis', 'blog'],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
# This docker-compose file is made for development purpose and build from source, if you want to use teddit in production, the README contains a production-ready docker-compose setup.
|
||||
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:6.2.5-alpine
|
||||
command: redis-server
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=master
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- teddit_net
|
||||
web:
|
||||
|
||||
teddit:
|
||||
container_name: teddit
|
||||
build: .
|
||||
environment:
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_HOST=teddit-redis
|
||||
ports:
|
||||
- 8080:8080
|
||||
- "8080:8080"
|
||||
networks:
|
||||
- teddit_net
|
||||
healthcheck:
|
||||
|
@ -23,6 +18,16 @@ services:
|
|||
interval: 1m
|
||||
timeout: 3s
|
||||
depends_on:
|
||||
- redis
|
||||
- teddit-redis
|
||||
|
||||
teddit-redis:
|
||||
container_name: teddit-redis
|
||||
image: redis:6.2.5-alpine
|
||||
command: redis-server
|
||||
environment:
|
||||
- REDIS_REPLICATION_MODE=master
|
||||
networks:
|
||||
- teddit_net
|
||||
|
||||
networks:
|
||||
teddit_net:
|
||||
|
|
118
inc/commons.js
118
inc/commons.js
|
@ -39,8 +39,10 @@ module.exports = function(request, fs) {
|
|||
this.teddifyUrl = (url, user_preferences) => {
|
||||
try {
|
||||
let u = new URL(url)
|
||||
let domain_replaced = false
|
||||
if(u.host === 'www.reddit.com' || u.host === 'reddit.com') {
|
||||
url = url.replace(u.host, config.domain)
|
||||
domain_replaced = true
|
||||
if(u.pathname.startsWith('/gallery/'))
|
||||
url = url.replace('/gallery/', '/comments/')
|
||||
}
|
||||
|
@ -50,10 +52,15 @@ module.exports = function(request, fs) {
|
|||
let file_ext = getFileExtension(url)
|
||||
if(image_exts.includes(file_ext))
|
||||
url = url.replace(`${u.host}/`, `${config.domain}/pics/w:null_`)
|
||||
domain_replaced = true
|
||||
if(video_exts.includes(file_ext) || !image_exts.includes(file_ext))
|
||||
url = url.replace(u.host, `${config.domain}/vids`) + '.mp4'
|
||||
domain_replaced = true
|
||||
}
|
||||
|
||||
if(domain_replaced && !config.https_enabled) {
|
||||
url = url.replace('https:', 'http:')
|
||||
}
|
||||
} catch(e) { }
|
||||
url = replaceDomains(url, user_preferences)
|
||||
return url
|
||||
|
@ -182,28 +189,113 @@ module.exports = function(request, fs) {
|
|||
|
||||
this.replaceUserDomains = (str, user_preferences) => {
|
||||
|
||||
let redditRegex = /([A-z.]+\.)?(reddit(\.com)|redd(\.it))/gm;
|
||||
let youtubeRegex = /([A-z.]+\.)?youtu(be\.com|\.be)/gm;
|
||||
let twitterRegex = /([A-z.]+\.)?twitter\.com/gm;
|
||||
let instagramRegex = /([A-z.]+\.)?instagram.com/gm;
|
||||
let redditRegex = /(?<=href=")(https?:\/\/)([A-z.]+\.)?(reddit(\.com)|redd(\.it))(?=.+")/gm;
|
||||
let youtubeRegex = /(?<=href=")(https?:\/\/)([A-z.]+\.)?youtu(be\.com|\.be)(?=.+")/gm;
|
||||
let twitterRegex = /(?<=href=")(https?:\/\/)(www\.)?twitter\.com(?=.+")/gm;
|
||||
let instagramRegex = /(?<=href=")(https?:\/\/)(www+\.)?instagram.com(?=.+")/gm;
|
||||
let quoraRegex = /(?<=href=")(https?:\/\/)([A-z.]+\.)?quora\.com(?=.+")/gm;
|
||||
|
||||
str = str.replace(redditRegex, config.domain)
|
||||
/*
|
||||
* regex pattern to replace imgur links (imgur.com, imgur.io, i.stack.imgur.com)
|
||||
* source: https://github.com/libredirect/libredirect/blob/32c4a0211e3b721d46219c05cba93f1a42cf3773/src/config/config.json#L317
|
||||
* license: GNU GPL v3 License -> https://github.com/libredirect/libredirect/blob/32c4a0211e3b721d46219c05cba93f1a42cf3773/LICENSE
|
||||
*/
|
||||
let imgurRegex = /(?<=href=")(https?:\/{2})([im]\.)?(stack\.)?imgur\.(com|io)(?=.+")/gm;
|
||||
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https://' : 'http://'
|
||||
|
||||
/**
|
||||
* Special handling for reddit media domains in comments hrefs or img srcs.
|
||||
* For example a comment might have a direct links to images in i.redd.it:
|
||||
* <a href="https://i.redd.it/hly9gyg9gjh81.png">Just refer to this </a>
|
||||
* We want to rewrite these hrefs, but we also need to include the domain
|
||||
* for our backend, so we know where to fetch the media from.
|
||||
* That comment URL then becomes like this after rewriting it:
|
||||
* <a href="https://teddit.net/hly9gyg9gjh81.png?teddit_proxy=i.redd.it">Just refer to this </a>
|
||||
* And then in our backend, we check if we have a 'teddit_proxy' in the req
|
||||
* query, and proceed to proxy if it does.
|
||||
*/
|
||||
const replacable_media_domains = ['i.redd.it', 'v.redd.it', 'external-preview.redd.it', 'preview.redd.it']
|
||||
replacable_media_domains.forEach((domain) => {
|
||||
if (str.includes(domain + "/")) {
|
||||
const regex = new RegExp(`(?<=(href|src)=")(https?:\/\/)([A-z.]+\.)?(${domain})(.+?(?="))`, 'gm')
|
||||
const hrefs = str.match(regex)
|
||||
if (!hrefs) {
|
||||
return
|
||||
}
|
||||
|
||||
hrefs.forEach((url) => {
|
||||
let original_url = url
|
||||
const valid_exts = ['png', 'jpg', 'jpeg', 'mp4', 'gif', 'gifv']
|
||||
const file_ext = getFileExtension(url)
|
||||
if (valid_exts.includes(file_ext)) {
|
||||
url = url.replace(domain, config.domain)
|
||||
|
||||
// append the domain info to the query, for teddit backend
|
||||
let u = new URL(url)
|
||||
if (u.search) {
|
||||
url += '&teddit_proxy=' + domain
|
||||
} else {
|
||||
url += '?teddit_proxy=' + domain
|
||||
}
|
||||
|
||||
// also replace the protocol for instances using http only
|
||||
if (protocol === 'http://' && u.protocol === 'https:') {
|
||||
url.replace('https://', protocol)
|
||||
}
|
||||
str = str.replace(original_url, url)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Continue the normal replace logic
|
||||
|
||||
str = str.replace(redditRegex, protocol + config.domain)
|
||||
|
||||
if(typeof(user_preferences) == 'undefined')
|
||||
return str
|
||||
|
||||
if(typeof(user_preferences.domain_youtube) != 'undefined')
|
||||
if(user_preferences.domain_youtube)
|
||||
str = str.replace(youtubeRegex, user_preferences.domain_youtube)
|
||||
if(user_preferences.domain_youtube){
|
||||
if (!youtubeRegex.test(str)){
|
||||
youtubeRegex = /(https?:\/\/)([A-z.]+\.)?youtu(be\.com|\.be)(?=.+)/gm;
|
||||
}
|
||||
str = str.replace(youtubeRegex, protocol + user_preferences.domain_youtube);
|
||||
}
|
||||
|
||||
if(typeof(user_preferences.domain_twitter) != 'undefined')
|
||||
if(user_preferences.domain_twitter)
|
||||
str = str.replace(twitterRegex, user_preferences.domain_twitter)
|
||||
|
||||
if(typeof(user_preferences.domain_instagram) != 'undefined')
|
||||
if(user_preferences.domain_instagram)
|
||||
str = str.replace(instagramRegex, user_preferences.domain_instagram)
|
||||
if(user_preferences.domain_twitter){
|
||||
if (!twitterRegex.test(str)){
|
||||
twitterRegex = /(https?:\/\/)(www\.)?twitter\.com(?=.)/gm;
|
||||
}
|
||||
str = str.replace(twitterRegex, protocol + user_preferences.domain_twitter)
|
||||
}
|
||||
|
||||
if(typeof(user_preferences.domain_instagram) != 'undefined'){
|
||||
if(user_preferences.domain_instagram){
|
||||
if (!instagramRegex.test(str)){
|
||||
instagramRegex = /(https?:\/\/)(www+\.)?instagram.com(?=.)/gm;
|
||||
}
|
||||
str = str.replace(instagramRegex, protocol + user_preferences.domain_instagram);
|
||||
}
|
||||
}
|
||||
if(typeof(user_preferences.domain_quora) != 'undefined'){
|
||||
if(user_preferences.domain_quora){
|
||||
if (!quoraRegex.test(str)){
|
||||
quoraRegex = /(https?:\/\/)([A-z.]+\.)?quora\.com(?=.)/gm;
|
||||
}
|
||||
str = str.replace(quoraRegex, protocol + user_preferences.domain_quora)
|
||||
}
|
||||
}
|
||||
if(typeof(user_preferences.domain_imgur) != 'undefined'){
|
||||
if(user_preferences.domain_imgur){
|
||||
if (!imgurRegex.test(str)){
|
||||
imgurRegex = /(https?:\/{2})([im]\.)?(stack\.)?imgur\.(com|io)(?=.)/gm;
|
||||
}
|
||||
str = str.replace(imgurRegex, protocol + user_preferences.domain_imgur)
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,15 @@ module.exports = function() {
|
|||
let comments_html
|
||||
function commentAuthor(comment, classlist, submitter, moderator) {
|
||||
let classes = classlist.join(' ')
|
||||
if (comment.author === '[deleted]')
|
||||
return `<span class="${classes}">[deleted]</span>`
|
||||
else
|
||||
if (comment.author === '[deleted]') {
|
||||
var reveddit_url = "https://www.reveddit.com" + post_url.substr(post_url.indexOf('/r/')) + comments.id
|
||||
return `<span class="${classes}"><a href="${reveddit_url}" style='color: #cc6a6a !important;'>[deleted]</a></span>`
|
||||
}
|
||||
|
||||
else {
|
||||
return `<a href="/u/${comment.author}" class="${classes}">${comment.author}</a>${submitter || ''}${moderator || ''}`
|
||||
}
|
||||
}
|
||||
|
||||
if(!user_preferences)
|
||||
user_preferences = {}
|
||||
|
@ -115,6 +119,7 @@ module.exports = function() {
|
|||
}
|
||||
} else {
|
||||
let link = comments.parent_id.split('_')[1]
|
||||
link = post_url + link
|
||||
comments_html = `
|
||||
<div class="load-more-comments">
|
||||
<a href="${link}/#c">continue this thread</a>
|
||||
|
@ -205,7 +210,7 @@ module.exports = function() {
|
|||
}
|
||||
comments_html += replies_html + '</details></div>'
|
||||
} else {
|
||||
if(comment.children.length > 0) {
|
||||
if(comment.children.length > 0) {
|
||||
let parent_id = comment.parent_id.split('_')[1]
|
||||
let load_comms_href = parent_id
|
||||
|
||||
|
@ -216,6 +221,7 @@ module.exports = function() {
|
|||
`
|
||||
} else {
|
||||
let link = comment.parent_id.split('_')[1]
|
||||
link = post_url + link
|
||||
comments_html = `
|
||||
<div class="load-more-comments">
|
||||
<a href="${link}/#c">continue this thread</a>
|
||||
|
|
|
@ -28,9 +28,15 @@ async function fromJson(data, user_preferences, subreddit_front) {
|
|||
result.domain = data.domain
|
||||
result.is_video = data.is_video
|
||||
result.media = data.media
|
||||
result.duration = data.is_video ? data.media.reddit_video ? data.media.reddit_video.duration : void 0 : void 0
|
||||
result.duration = null
|
||||
result.images = null
|
||||
|
||||
if(data.is_video && data.media) {
|
||||
if(data.media.reddit_video) {
|
||||
result.duration = data.media.reddit_video.duration
|
||||
}
|
||||
}
|
||||
|
||||
// Moderation attributes
|
||||
result.locked = data.locked
|
||||
result.stickied = data.stickied
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = function(fetch) {
|
|||
} else {
|
||||
console.error(`Something went wrong while trying to get an access token from reddit API. ${result.status} – ${result.statusText}`)
|
||||
console.error(reddit_api_error_text)
|
||||
return res.render('index', { json: null, http_status_code: result.status })
|
||||
return res.render('frontpage', { json: null, http_status_code: result.status, instance_config: config })
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(`Error while obtaining a reddit API key.`, error)
|
||||
|
@ -66,14 +66,14 @@ module.exports = function(fetch) {
|
|||
} else {
|
||||
console.error(`Something went wrong while fetching data from reddit API. ${result.status} – ${result.statusText}`)
|
||||
console.error(reddit_api_error_text)
|
||||
return res.render('index', { json: null, http_status_code: result.status })
|
||||
return res.render('frontpage', { json: null, http_status_code: result.status, instance_config: config })
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(`Error while refreshing the reddit API key.`, error)
|
||||
})
|
||||
}
|
||||
this.redditApiGETHeaders = function() {
|
||||
let cookies = '_options=%7B%22pref_quarantine_optin%22%3A%20true%7D'
|
||||
let cookies = `edgebucket=; _options={%22pref_gated_sr_optin%22:true,%22pref_quarantine_optin%22:true}`
|
||||
|
||||
if(!config.use_reddit_oauth)
|
||||
return { headers: { cookie: cookies }, method: 'GET' }
|
||||
|
|
|
@ -1,16 +1,136 @@
|
|||
module.exports = function(fetch) {
|
||||
var compilePostComments = require('./compilePostComments.js')();
|
||||
var procPostMedia = require('./processPostMedia.js')();
|
||||
this.processJsonPost = (json, parsed, user_preferences) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(!parsed) {
|
||||
json = JSON.parse(json)
|
||||
const compilePostComments = require('./compilePostComments.js')();
|
||||
const procPostMedia = require('./processPostMedia.js')();
|
||||
const config = require('../config');
|
||||
|
||||
async function processReplies(data, post_id, depth, user_preferences) {
|
||||
let return_replies = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
let kind = data[i].kind;
|
||||
let reply = data[i].data;
|
||||
let obj = {};
|
||||
if (kind !== 'more') {
|
||||
obj = {
|
||||
author: reply.author,
|
||||
body_html: reply.body_html,
|
||||
parent_id: reply.parent_id,
|
||||
created: reply.created_utc,
|
||||
edited: reply.edited,
|
||||
score: reply.score,
|
||||
ups: reply.ups,
|
||||
id: reply.id,
|
||||
permalink: teddifyUrl(reply.permalink),
|
||||
stickied: reply.stickied,
|
||||
distinguished: reply.distinguished,
|
||||
score_hidden: reply.score_hidden,
|
||||
edited: reply.edited,
|
||||
replies: [],
|
||||
depth: depth,
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false'
|
||||
? await formatUserFlair(reply)
|
||||
: '',
|
||||
controversiality:
|
||||
user_preferences.highlight_controversial != 'false'
|
||||
? reply.controversiality
|
||||
: '',
|
||||
};
|
||||
} else {
|
||||
obj = {
|
||||
type: 'load_more',
|
||||
count: reply.count,
|
||||
id: reply.id,
|
||||
parent_id: reply.parent_id,
|
||||
post_id: post_id,
|
||||
children: [],
|
||||
depth: depth,
|
||||
};
|
||||
}
|
||||
|
||||
let post = json[0].data.children[0].data
|
||||
let post_id = post.name
|
||||
let comments = json[1].data.children
|
||||
if (reply.replies && kind !== 'more') {
|
||||
if (reply.replies.data.children.length) {
|
||||
for (var j = 0; j < reply.replies.data.children.length; j++) {
|
||||
let comment = reply.replies.data.children[j].data;
|
||||
let objct = {};
|
||||
|
||||
if (comment.author && comment.body_html) {
|
||||
objct = {
|
||||
author: comment.author,
|
||||
body_html: comment.body_html,
|
||||
parent_id: comment.parent_id,
|
||||
created: comment.created_utc,
|
||||
edited: comment.edited,
|
||||
score: comment.score,
|
||||
ups: comment.ups,
|
||||
id: comment.id,
|
||||
permalink: teddifyUrl(comment.permalink),
|
||||
score_hidden: comment.score_hidden,
|
||||
distinguished: comment.distinguished,
|
||||
distinguished: comment.edited,
|
||||
replies: [],
|
||||
depth: depth + 1,
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false'
|
||||
? await formatUserFlair(comment)
|
||||
: '',
|
||||
controversiality:
|
||||
user_preferences.highlight_controversial != 'false'
|
||||
? comment.controversiality
|
||||
: '',
|
||||
};
|
||||
} else {
|
||||
objct = {
|
||||
type: 'load_more',
|
||||
count: comment.count,
|
||||
id: comment.id,
|
||||
parent_id: comment.parent_id,
|
||||
post_id: post_id,
|
||||
children: [],
|
||||
depth: depth + 1,
|
||||
};
|
||||
if (comment.children) {
|
||||
for (var k = 0; k < comment.children.length; k++) {
|
||||
objct.children.push(comment.children[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (comment.replies) {
|
||||
if (comment.replies.data) {
|
||||
if (comment.replies.data.children.length > 0) {
|
||||
objct.replies = await processReplies(
|
||||
comment.replies.data.children,
|
||||
post_id,
|
||||
depth,
|
||||
user_preferences
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj.replies.push(objct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reply.children) {
|
||||
for (var j = 0; j < reply.children.length; j++) {
|
||||
obj.children.push(reply.children[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return_replies.push(obj);
|
||||
}
|
||||
return return_replies;
|
||||
}
|
||||
|
||||
async function processJsonPost(json, parsed, user_preferences) {
|
||||
if (!parsed) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
|
||||
let post = json[0].data.children[0].data;
|
||||
let post_id = post.name;
|
||||
let comments = json[1].data.children;
|
||||
|
||||
let obj = {
|
||||
author: post.author,
|
||||
|
@ -36,53 +156,71 @@ module.exports = function(fetch) {
|
|||
images: null,
|
||||
crosspost: false,
|
||||
selftext: unescape(post.selftext_html),
|
||||
selftext_preview: post.selftext.substr(0, 120).replace(/\n/g, ' '),
|
||||
poll_data: post.poll_data,
|
||||
link_flair: (user_preferences.flairs != 'false' ? await formatLinkFlair(post) : ''),
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(post) : '')
|
||||
}
|
||||
link_flair:
|
||||
user_preferences.flairs != 'false' ? await formatLinkFlair(post) : '',
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false' ? await formatUserFlair(post) : '',
|
||||
};
|
||||
|
||||
let valid_embed_video_domains = ['gfycat.com']
|
||||
let has_gif = false
|
||||
let gif_to_mp4 = null
|
||||
let reddit_video = null
|
||||
let embed_video = false
|
||||
let valid_embed_video_domains = ['gfycat.com'];
|
||||
let has_gif = false;
|
||||
let gif_to_mp4 = null;
|
||||
let reddit_video = null;
|
||||
let embed_video = false;
|
||||
|
||||
if(post.media)
|
||||
if(valid_embed_video_domains.includes(post.media.type))
|
||||
embed_video = true
|
||||
if (post.media)
|
||||
if (valid_embed_video_domains.includes(post.media.type)) embed_video = true;
|
||||
|
||||
if(post.preview && !embed_video) {
|
||||
if(post.preview.reddit_video_preview) {
|
||||
if(post.preview.reddit_video_preview.is_gif) {
|
||||
has_gif = true
|
||||
gif_url = post.preview.reddit_video_preview.fallback_url
|
||||
if (post.preview && !embed_video) {
|
||||
if (post.preview.reddit_video_preview) {
|
||||
if (post.preview.reddit_video_preview.is_gif) {
|
||||
has_gif = true;
|
||||
gif_url = post.preview.reddit_video_preview.fallback_url;
|
||||
} else {
|
||||
let file_ext = getFileExtension(post.preview.reddit_video_preview.fallback_url)
|
||||
if(file_ext === 'mp4') {
|
||||
post.media = true
|
||||
reddit_video = post.preview.reddit_video_preview
|
||||
let file_ext = getFileExtension(
|
||||
post.preview.reddit_video_preview.fallback_url
|
||||
);
|
||||
if (file_ext === 'mp4') {
|
||||
post.media = true;
|
||||
reddit_video = post.preview.reddit_video_preview;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(post.preview.images) {
|
||||
if(post.preview.images[0].source) {
|
||||
let file_ext = getFileExtension(post.preview.images[0].source.url)
|
||||
if(file_ext === 'gif') {
|
||||
has_gif = true
|
||||
let resolutions = post.preview.images[0].variants.mp4.resolutions
|
||||
gif_to_mp4 = resolutions[resolutions.length - 1]
|
||||
if (post.preview.images) {
|
||||
if (post.preview.images[0].source) {
|
||||
let file_ext = getFileExtension(post.preview.images[0].source.url);
|
||||
if (file_ext === 'gif') {
|
||||
has_gif = true;
|
||||
let resolutions = post.preview.images[0].variants.mp4.resolutions;
|
||||
gif_to_mp4 = resolutions[resolutions.length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = await processPostMedia(obj, post, post.media, has_gif, reddit_video, gif_to_mp4)
|
||||
obj = await processPostMedia(
|
||||
obj,
|
||||
post,
|
||||
post.media,
|
||||
has_gif,
|
||||
reddit_video,
|
||||
gif_to_mp4
|
||||
);
|
||||
|
||||
if(post.crosspost_parent_list) {
|
||||
post.crosspost = post.crosspost_parent_list[0]
|
||||
if (post.crosspost_parent_list) {
|
||||
post.crosspost = post.crosspost_parent_list[0];
|
||||
}
|
||||
if(post.crosspost) {
|
||||
obj = await processPostMedia(obj, post.crosspost, post.crosspost.media, has_gif, reddit_video, gif_to_mp4)
|
||||
if (post.crosspost) {
|
||||
obj = await processPostMedia(
|
||||
obj,
|
||||
post.crosspost,
|
||||
post.crosspost.media,
|
||||
has_gif,
|
||||
reddit_video,
|
||||
gif_to_mp4
|
||||
);
|
||||
obj.crosspost = {
|
||||
author: post.crosspost.author,
|
||||
created: post.crosspost.created_utc,
|
||||
|
@ -98,57 +236,67 @@ module.exports = function(fetch) {
|
|||
selftext_crosspost: unescape(post.crosspost.selftext_html),
|
||||
poll_data: post.poll_data,
|
||||
is_crosspost: true,
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(post) : '')
|
||||
}
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false' ? await formatUserFlair(post) : '',
|
||||
};
|
||||
}
|
||||
|
||||
if(post.preview && !obj.has_media) {
|
||||
if (post.preview && !obj.has_media) {
|
||||
obj.images = {
|
||||
source: await downloadAndSave(post.preview.images[0].source.url)
|
||||
}
|
||||
source: await downloadAndSave(post.preview.images[0].source.url),
|
||||
};
|
||||
}
|
||||
|
||||
if(obj.media) {
|
||||
if(obj.media.source === 'external') {
|
||||
if(post.preview) {
|
||||
if (obj.media) {
|
||||
if (obj.media.source === 'external') {
|
||||
if (post.preview) {
|
||||
obj.images = {
|
||||
source: await downloadAndSave(post.preview.images[0].source.url)
|
||||
}
|
||||
source: await downloadAndSave(post.preview.images[0].source.url),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(post.gallery_data) {
|
||||
obj.gallery = true
|
||||
obj.gallery_items = []
|
||||
for(var i = 0; i < post.gallery_data.items.length; i++) {
|
||||
let id = post.gallery_data.items[i].media_id
|
||||
if(post.media_metadata[id]) {
|
||||
if(post.media_metadata[id].p) {
|
||||
if(post.media_metadata[id].p[0]) {
|
||||
let item = { source: null, thumbnail: null, large: null }
|
||||
if(post.media_metadata[id].s && post.media_metadata[id].p[0].u) {
|
||||
if (post.gallery_data) {
|
||||
obj.gallery = true;
|
||||
obj.gallery_items = [];
|
||||
for (var i = 0; i < post.gallery_data.items.length; i++) {
|
||||
let id = post.gallery_data.items[i].media_id;
|
||||
if (post.media_metadata) {
|
||||
if (post.media_metadata[id]) {
|
||||
if (post.media_metadata[id].p) {
|
||||
if (post.media_metadata[id].p[0]) {
|
||||
let item = { source: null, thumbnail: null, large: null };
|
||||
if (post.media_metadata[id].s && post.media_metadata[id].p[0].u) {
|
||||
item = {
|
||||
type: post.media_metadata[id].e,
|
||||
source: await downloadAndSave(post.media_metadata[id].s.u),
|
||||
thumbnail: await downloadAndSave(post.media_metadata[id].p[0].u),
|
||||
large: await downloadAndSave(post.media_metadata[id].p[post.media_metadata[id].p.length - 1].u),
|
||||
thumbnail: await downloadAndSave(
|
||||
post.media_metadata[id].p[0].u
|
||||
),
|
||||
large: await downloadAndSave(
|
||||
post.media_metadata[id].p[
|
||||
post.media_metadata[id].p.length - 1
|
||||
].u
|
||||
),
|
||||
caption: post.gallery_data.items[i].caption || false,
|
||||
};
|
||||
}
|
||||
obj.gallery_items.push(item);
|
||||
}
|
||||
obj.gallery_items.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let comms = []
|
||||
for(var i = 0; i < comments.length; i++) {
|
||||
let comment = comments[i].data
|
||||
let kind = comments[i].kind
|
||||
let obj = {}
|
||||
let comms = [];
|
||||
for (var i = 0; i < comments.length; i++) {
|
||||
let comment = comments[i].data;
|
||||
let kind = comments[i].kind;
|
||||
let obj = {};
|
||||
|
||||
if(kind !== 'more') {
|
||||
if (kind !== 'more') {
|
||||
obj = {
|
||||
author: comment.author,
|
||||
body_html: comment.body_html,
|
||||
|
@ -165,9 +313,15 @@ module.exports = function(fetch) {
|
|||
edited: comment.edited,
|
||||
replies: [],
|
||||
depth: comment.depth,
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(comment) : ''),
|
||||
controversiality: (user_preferences.highlight_controversial != 'false' ? comment.controversiality : '')
|
||||
}
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false'
|
||||
? await formatUserFlair(comment)
|
||||
: '',
|
||||
controversiality:
|
||||
user_preferences.highlight_controversial != 'false'
|
||||
? comment.controversiality
|
||||
: '',
|
||||
};
|
||||
} else {
|
||||
obj = {
|
||||
type: 'load_more',
|
||||
|
@ -175,158 +329,212 @@ module.exports = function(fetch) {
|
|||
id: comment.id,
|
||||
parent_id: comment.parent_id,
|
||||
post_id: post.name,
|
||||
children: []
|
||||
}
|
||||
}
|
||||
|
||||
if(comment.replies && kind !== 'more') {
|
||||
if(comment.replies.data) {
|
||||
if(comment.replies.data.children.length > 0) {
|
||||
obj.replies = await processReplies(comment.replies.data.children, post_id, 1, user_preferences)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(comment.children) {
|
||||
for(var j = 0; j < comment.children.length; j++) {
|
||||
obj.children.push(comment.children[j])
|
||||
}
|
||||
}
|
||||
|
||||
comms.push(obj)
|
||||
}
|
||||
|
||||
obj.comments = comms
|
||||
|
||||
resolve(obj)
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
this.finalizeJsonPost = async (processed_json, post_id, post_url, morechildren_ids, viewing_comment, user_preferences) => {
|
||||
let comments_html = `<div class="comments">`
|
||||
let comments = processed_json.comments
|
||||
let last_known_depth = undefined
|
||||
for(var i = 0; i < comments.length; i++) {
|
||||
let next_comment = false
|
||||
if(comments[i+1]) {
|
||||
next_comment = comments[i+1]
|
||||
}
|
||||
if(comments[i].depth != undefined) {
|
||||
last_known_depth = comments[i].depth
|
||||
}
|
||||
|
||||
comments_html += await compilePostCommentsHtml(comments[i], next_comment, post_id, post_url, morechildren_ids, processed_json.author, viewing_comment, user_preferences, last_known_depth)
|
||||
}
|
||||
|
||||
comments_html += `</div>`
|
||||
|
||||
delete processed_json['comments']
|
||||
let post_data = processed_json
|
||||
return { post_data: post_data, comments: comments_html }
|
||||
}
|
||||
|
||||
this.processReplies = async (data, post_id, depth, user_preferences) => {
|
||||
let return_replies = []
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
let kind = data[i].kind
|
||||
let reply = data[i].data
|
||||
let obj = {}
|
||||
if(kind !== 'more') {
|
||||
obj = {
|
||||
author: reply.author,
|
||||
body_html: reply.body_html,
|
||||
parent_id: reply.parent_id,
|
||||
created: reply.created_utc,
|
||||
edited: reply.edited,
|
||||
score: reply.score,
|
||||
ups: reply.ups,
|
||||
id: reply.id,
|
||||
permalink: teddifyUrl(reply.permalink),
|
||||
stickied: reply.stickied,
|
||||
distinguished: reply.distinguished,
|
||||
score_hidden: reply.score_hidden,
|
||||
edited: reply.edited,
|
||||
replies: [],
|
||||
depth: depth,
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(reply) : ''),
|
||||
controversiality: (user_preferences.highlight_controversial != 'false' ? reply.controversiality : '')
|
||||
}
|
||||
} else {
|
||||
obj = {
|
||||
type: 'load_more',
|
||||
count: reply.count,
|
||||
id: reply.id,
|
||||
parent_id: reply.parent_id,
|
||||
post_id: post_id,
|
||||
children: [],
|
||||
depth: depth
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if(reply.replies && kind !== 'more') {
|
||||
if(reply.replies.data.children.length) {
|
||||
for(var j = 0; j < reply.replies.data.children.length; j++) {
|
||||
let comment = reply.replies.data.children[j].data
|
||||
let objct = {}
|
||||
|
||||
if(comment.author && comment.body_html) {
|
||||
objct = {
|
||||
author: comment.author,
|
||||
body_html: comment.body_html,
|
||||
parent_id: comment.parent_id,
|
||||
created: comment.created_utc,
|
||||
edited: comment.edited,
|
||||
score: comment.score,
|
||||
ups: comment.ups,
|
||||
id: comment.id,
|
||||
permalink: teddifyUrl(comment.permalink),
|
||||
score_hidden: comment.score_hidden,
|
||||
distinguished: comment.distinguished,
|
||||
distinguished: comment.edited,
|
||||
replies: [],
|
||||
depth: depth + 1,
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(comment) : ''),
|
||||
controversiality: (user_preferences.highlight_controversial != 'false' ? comment.controversiality : '')
|
||||
}
|
||||
} else {
|
||||
objct = {
|
||||
type: 'load_more',
|
||||
count: comment.count,
|
||||
id: comment.id,
|
||||
parent_id: comment.parent_id,
|
||||
post_id: post_id,
|
||||
children: [],
|
||||
depth: depth + 1
|
||||
}
|
||||
if(comment.children) {
|
||||
for(var k = 0; k < comment.children.length; k++) {
|
||||
objct.children.push(comment.children[k])
|
||||
if (comment.replies && kind !== 'more') {
|
||||
if (comment.replies.data) {
|
||||
if (comment.replies.data.children.length > 0) {
|
||||
obj.replies = await processReplies(
|
||||
comment.replies.data.children,
|
||||
post_id,
|
||||
1,
|
||||
user_preferences
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(comment.replies) {
|
||||
if(comment.replies.data) {
|
||||
if(comment.replies.data.children.length > 0) {
|
||||
objct.replies = await processReplies(comment.replies.data.children, post_id, depth, user_preferences)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj.replies.push(objct)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(reply.children) {
|
||||
for(var j = 0; j < reply.children.length; j++) {
|
||||
obj.children.push(reply.children[j])
|
||||
if (comment.children) {
|
||||
for (var j = 0; j < comment.children.length; j++) {
|
||||
obj.children.push(comment.children[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return_replies.push(obj)
|
||||
}
|
||||
return return_replies
|
||||
comms.push(obj);
|
||||
}
|
||||
|
||||
obj.comments = comms;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
async function finalizeJsonPost(
|
||||
processed_json,
|
||||
post_id,
|
||||
post_url,
|
||||
morechildren_ids,
|
||||
viewing_comment,
|
||||
user_preferences
|
||||
) {
|
||||
let comments_html = `<div class="comments">`;
|
||||
let comments = processed_json.comments;
|
||||
let last_known_depth = undefined;
|
||||
for (var i = 0; i < comments.length; i++) {
|
||||
let next_comment = false;
|
||||
if (comments[i + 1]) {
|
||||
next_comment = comments[i + 1];
|
||||
}
|
||||
if (comments[i].depth != undefined) {
|
||||
last_known_depth = comments[i].depth;
|
||||
}
|
||||
|
||||
comments_html += await compilePostCommentsHtml(
|
||||
comments[i],
|
||||
next_comment,
|
||||
post_id,
|
||||
post_url,
|
||||
morechildren_ids,
|
||||
processed_json.author,
|
||||
viewing_comment,
|
||||
user_preferences,
|
||||
last_known_depth
|
||||
);
|
||||
}
|
||||
|
||||
comments_html += `</div>`;
|
||||
|
||||
delete processed_json['comments'];
|
||||
let post_data = processed_json;
|
||||
return { post_data: post_data, comments: comments_html };
|
||||
}
|
||||
|
||||
async function processJsonPostList(posts, mode) {
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
|
||||
for (var i = 0; i < posts.length; i++) {
|
||||
let link = posts[i];
|
||||
let valid_reddit_self_domains = ['reddit.com'];
|
||||
let is_self_link = false;
|
||||
|
||||
if (link.domain) {
|
||||
let tld = link.domain.split('self.');
|
||||
if (tld.length > 1) {
|
||||
if (!tld[1].includes('.')) {
|
||||
is_self_link = true;
|
||||
link.url = teddifyUrl(link.url);
|
||||
}
|
||||
}
|
||||
if (
|
||||
config.valid_media_domains.includes(link.domain) ||
|
||||
valid_reddit_self_domains.includes(link.domain)
|
||||
) {
|
||||
is_self_link = true;
|
||||
link.url = teddifyUrl(link.url);
|
||||
}
|
||||
}
|
||||
|
||||
link.permalink = `${protocol}://${config.domain}${link.permalink}`;
|
||||
|
||||
if (is_self_link) link.url = link.permalink;
|
||||
|
||||
if (link.images) {
|
||||
if (link.images.thumb !== 'self') {
|
||||
link.images.thumb = `${protocol}://${config.domain}${link.images.thumb}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode === 'light') {
|
||||
link.selftext_html = null;
|
||||
}
|
||||
}
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
async function getPostItem(post_json, req, protocol) {
|
||||
let thumbnail = '';
|
||||
let post_image = '';
|
||||
let is_self_link = false;
|
||||
let valid_reddit_self_domains = ['reddit.com'];
|
||||
|
||||
if (post_json.domain) {
|
||||
let tld = post_json.domain.split('self.');
|
||||
if (tld.length > 1) {
|
||||
if (!tld[1].includes('.')) {
|
||||
is_self_link = true;
|
||||
post_json.url = teddifyUrl(post_json.url);
|
||||
}
|
||||
}
|
||||
if (
|
||||
config.valid_media_domains.includes(post_json.domain) ||
|
||||
valid_reddit_self_domains.includes(post_json.domain)
|
||||
) {
|
||||
is_self_link = true;
|
||||
post_json.url = teddifyUrl(post_json.url);
|
||||
}
|
||||
}
|
||||
|
||||
if (post_json.preview && post_json.thumbnail !== 'self') {
|
||||
if (!post_json.url.startsWith('/r/') && isGif(post_json.url)) {
|
||||
let s = await downloadAndSave(post_json.thumbnail, 'thumb_');
|
||||
thumbnail = `${protocol}://${config.domain}${s}`;
|
||||
} else {
|
||||
if (post_json.preview.images[0].resolutions[0]) {
|
||||
let s = await downloadAndSave(
|
||||
post_json.preview.images[0].resolutions[0].url,
|
||||
'thumb_'
|
||||
);
|
||||
thumbnail = `${protocol}://${config.domain}${s}`;
|
||||
if (!isGif(post_json.url) && !post_json.post_hint.includes(':video')) {
|
||||
s = await downloadAndSave(post_json.preview.images[0].source.url);
|
||||
post_image = `${protocol}://${config.domain}${s}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post_json.permalink = `${protocol}://${config.domain}${post_json.permalink}`;
|
||||
|
||||
if (is_self_link) post_json.url = post_json.permalink;
|
||||
|
||||
if (req.query.hasOwnProperty('full_thumbs')) {
|
||||
if (!post_image) post_image = thumbnail;
|
||||
|
||||
thumbnail = post_image;
|
||||
}
|
||||
|
||||
let enclosure = '';
|
||||
if (thumbnail != '') {
|
||||
let mime = '';
|
||||
let ext = thumbnail.split('.').pop();
|
||||
if (ext === 'png') mime = 'image/png';
|
||||
else mime = 'image/jpeg';
|
||||
enclosure = `<enclosure length="0" type="${mime}" url="${thumbnail}" />`;
|
||||
}
|
||||
|
||||
let append_desc_html = `<br/><a href="${post_json.url}">[link]</a> <a href="${post_json.permalink}">[comments]</a>`;
|
||||
|
||||
return `
|
||||
<item>
|
||||
<title>${post_json.title}</title>
|
||||
<author>${post_json.author}</author>
|
||||
<created>${post_json.created}</created>
|
||||
<pubDate>${new Date(
|
||||
post_json.created_utc * 1000
|
||||
).toGMTString()}</pubDate>
|
||||
<domain>${post_json.domain}</domain>
|
||||
<id>${post_json.id}</id>
|
||||
<thumbnail>${thumbnail}</thumbnail>
|
||||
${enclosure}
|
||||
<link>${post_json.permalink}</link>
|
||||
<url>${post_json.url}</url>
|
||||
<description><![CDATA[${unescape(
|
||||
post_json.selftext_html
|
||||
)}${append_desc_html}]]></description>
|
||||
<num_comments>${post_json.num_comments}</num_comments>
|
||||
<ups>${post_json.ups}</ups>
|
||||
<stickied>${post_json.stickied}</stickied>
|
||||
<is_self_link>${is_self_link}</is_self_link>
|
||||
</item>
|
||||
`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processReplies,
|
||||
processJsonPost,
|
||||
finalizeJsonPost,
|
||||
processJsonPostList,
|
||||
getPostItem
|
||||
};
|
||||
|
|
|
@ -1,45 +1,53 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config');
|
||||
const link = require('./components/link')
|
||||
this.processJsonSubreddit = (json, from, subreddit_front, user_preferences, saved) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(from === 'redis') {
|
||||
json = JSON.parse(json)
|
||||
const config = require('../config');
|
||||
const link = require('./components/link');
|
||||
|
||||
async function processJsonSubreddit(
|
||||
json,
|
||||
from,
|
||||
subreddit_front,
|
||||
user_preferences,
|
||||
saved
|
||||
) {
|
||||
if (from === 'redis') {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
if(json.error) {
|
||||
resolve({ error: true, error_data: json })
|
||||
if (json.error) {
|
||||
return { error: true, error_data: json };
|
||||
} else {
|
||||
if(saved) {
|
||||
if (saved) {
|
||||
let t = {
|
||||
data: {
|
||||
data: {
|
||||
before: null,
|
||||
after: null,
|
||||
children: json
|
||||
}
|
||||
}
|
||||
json = t
|
||||
children: json,
|
||||
},
|
||||
};
|
||||
json = t;
|
||||
}
|
||||
|
||||
let before = json.data.before
|
||||
let after = json.data.after
|
||||
let before = json.data.before;
|
||||
let after = json.data.after;
|
||||
|
||||
let ret = {
|
||||
info: {
|
||||
before: before,
|
||||
after: after
|
||||
after: after,
|
||||
},
|
||||
links: []
|
||||
}
|
||||
links: [],
|
||||
};
|
||||
|
||||
let children_len = json.data.children.length
|
||||
let children_len = json.data.children.length;
|
||||
|
||||
for(var i = 0; i < children_len; i++) {
|
||||
let data = json.data.children[i].data
|
||||
for (var i = 0; i < children_len; i++) {
|
||||
let data = json.data.children[i].data;
|
||||
|
||||
if(data.over_18)
|
||||
if((config.nsfw_enabled === false && user_preferences.nsfw_enabled != 'true') || user_preferences.nsfw_enabled === 'false')
|
||||
continue
|
||||
if (data.over_18)
|
||||
if (
|
||||
(config.nsfw_enabled === false &&
|
||||
user_preferences.nsfw_enabled != 'true') ||
|
||||
user_preferences.nsfw_enabled === 'false'
|
||||
)
|
||||
continue;
|
||||
|
||||
/*
|
||||
// Todo: Remove this once the link component is done
|
||||
|
@ -71,13 +79,12 @@ module.exports = function() {
|
|||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(data) : '')
|
||||
} */
|
||||
|
||||
let obj = await link.fromJson(data, user_preferences, subreddit_front)
|
||||
let obj = await link.fromJson(data, user_preferences, subreddit_front);
|
||||
|
||||
ret.links.push(obj)
|
||||
ret.links.push(obj);
|
||||
}
|
||||
resolve(ret)
|
||||
}
|
||||
})()
|
||||
})
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processJsonSubreddit;
|
||||
|
|
|
@ -1,59 +1,100 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config');
|
||||
const link = require('./components/link')
|
||||
this.processJsonUser = function(json, parsed, after, before, user_preferences, kind, post_type) {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(!parsed) {
|
||||
json = JSON.parse(json)
|
||||
const config = require('../config');
|
||||
const link = require('./components/link');
|
||||
|
||||
async function processJsonUser(
|
||||
json,
|
||||
parsed,
|
||||
after,
|
||||
before,
|
||||
user_preferences,
|
||||
kind,
|
||||
post_type
|
||||
) {
|
||||
if (!parsed) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
|
||||
let about = json.about.data
|
||||
let posts = []
|
||||
let view_more_posts = false
|
||||
let posts_limit = 25
|
||||
let user_front = false
|
||||
function validateJson(json) {
|
||||
const empty = {
|
||||
username: '',
|
||||
icon_img: '',
|
||||
created: '',
|
||||
verified: '',
|
||||
link_karma: '',
|
||||
comment_karma: '',
|
||||
view_more_posts: '',
|
||||
user_front: '',
|
||||
post_type:'',
|
||||
before: '',
|
||||
after: '',
|
||||
posts: [],
|
||||
};
|
||||
|
||||
if(json.overview.data.children.length > posts_limit) {
|
||||
view_more_posts = true
|
||||
if (!json.overview) {
|
||||
return { error: true, data: empty };
|
||||
}
|
||||
|
||||
if (!json.overview.data) {
|
||||
return { error: true, data: empty };
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const validJson = validateJson(json);
|
||||
if (validJson.error) {
|
||||
return validJson.data
|
||||
}
|
||||
|
||||
let about = json.about.data;
|
||||
let posts = [];
|
||||
let view_more_posts = false;
|
||||
let posts_limit = 25;
|
||||
let user_front = false;
|
||||
|
||||
if (json.overview.data.children.length > posts_limit) {
|
||||
view_more_posts = true;
|
||||
} else {
|
||||
posts_limit = json.overview.data.children.length
|
||||
posts_limit = json.overview.data.children.length;
|
||||
}
|
||||
|
||||
if(!after && !before) {
|
||||
user_front = true
|
||||
if (!after && !before) {
|
||||
user_front = true;
|
||||
}
|
||||
|
||||
if(json.overview.data.children) {
|
||||
if(json.overview.data.children[posts_limit - 1]) {
|
||||
after = json.overview.data.children[posts_limit - 1].data.name
|
||||
if (json.overview.data.children) {
|
||||
if (json.overview.data.children[posts_limit - 1]) {
|
||||
after = json.overview.data.children[posts_limit - 1].data.name;
|
||||
}
|
||||
if(json.overview.data.children[0]) {
|
||||
before = json.overview.data.children[0].data.name
|
||||
if (json.overview.data.children[0]) {
|
||||
before = json.overview.data.children[0].data.name;
|
||||
}
|
||||
}
|
||||
|
||||
for(var i = 0; i < posts_limit; i++) {
|
||||
let post = json.overview.data.children[i].data
|
||||
let thumbnail = 'self'
|
||||
let type = json.overview.data.children[i].kind
|
||||
let obj
|
||||
for (var i = 0; i < posts_limit; i++) {
|
||||
let post = json.overview.data.children[i].data;
|
||||
let thumbnail = 'self';
|
||||
let type = json.overview.data.children[i].kind;
|
||||
let obj;
|
||||
|
||||
let post_id = post.permalink.split('/').slice(-2)[0] + '/'
|
||||
let url = post.permalink.replace(post_id, '')
|
||||
let post_id = post.permalink.split('/').slice(-2)[0] + '/';
|
||||
let url = post.permalink.replace(post_id, '');
|
||||
|
||||
if(type !== kind && kind)
|
||||
continue
|
||||
if (type !== kind && kind) continue;
|
||||
|
||||
if(post.over_18)
|
||||
if((config.nsfw_enabled === false && user_preferences.nsfw_enabled != 'true') || user_preferences.nsfw_enabled === 'false')
|
||||
continue
|
||||
if (post.over_18)
|
||||
if (
|
||||
(config.nsfw_enabled === false &&
|
||||
user_preferences.nsfw_enabled != 'true') ||
|
||||
user_preferences.nsfw_enabled === 'false'
|
||||
)
|
||||
continue;
|
||||
|
||||
if(type === 't3') {
|
||||
obj = await link.fromJson(post, user_preferences)
|
||||
obj.type = 't3'
|
||||
if (type === 't3') {
|
||||
obj = await link.fromJson(post, user_preferences);
|
||||
obj.type = 't3';
|
||||
}
|
||||
if(type === 't1') {
|
||||
if (type === 't1') {
|
||||
obj = {
|
||||
type: type,
|
||||
subreddit: post.subreddit,
|
||||
|
@ -69,15 +110,16 @@ module.exports = function() {
|
|||
permalink: post.permalink,
|
||||
link_author: post.link_author,
|
||||
link_title: post.link_title,
|
||||
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(post) : '')
|
||||
user_flair:
|
||||
user_preferences.flairs != 'false' ? await formatUserFlair(post) : '',
|
||||
};
|
||||
}
|
||||
}
|
||||
posts.push(obj)
|
||||
posts.push(obj);
|
||||
}
|
||||
|
||||
let obj = {
|
||||
username: about.name,
|
||||
icon_img: await downloadAndSave(about.icon_img, "icon_"),
|
||||
icon_img: await downloadAndSave(about.icon_img, 'icon_'),
|
||||
created: about.created_utc,
|
||||
verified: about.verified,
|
||||
link_karma: about.link_karma,
|
||||
|
@ -87,11 +129,10 @@ module.exports = function() {
|
|||
post_type: post_type,
|
||||
before: before,
|
||||
after: after,
|
||||
posts: posts
|
||||
}
|
||||
posts: posts,
|
||||
};
|
||||
|
||||
resolve(obj)
|
||||
})()
|
||||
})
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
module.exports = processJsonUser;
|
||||
|
|
|
@ -1,54 +1,51 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config')
|
||||
this.moreComments = (fetch, redis, post_url, comment_ids, id) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
const config = require('../config');
|
||||
const { redisAsync } = require('./redis');
|
||||
|
||||
async function processMoreComments(fetch, redis, post_url, comment_ids, id) {
|
||||
if (post_url) {
|
||||
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`
|
||||
redis.get(key, (error, json) => {
|
||||
if(error) {
|
||||
console.error(`Error getting the ${key} key from redis (moreComments()).`, error)
|
||||
resolve(false)
|
||||
|
||||
try {
|
||||
const cached = await redisAsync.get(key);
|
||||
|
||||
if (cached !== null) {
|
||||
return JSON.parse(cached);
|
||||
}
|
||||
if(json) {
|
||||
json = JSON.parse(json)
|
||||
resolve(json)
|
||||
} else {
|
||||
let url = `https://oauth.reddit.com/api/morechildren?api_type=json&children=${comment_ids}&limit_children=false&link_id=t3_${id}`
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
.then(result => {
|
||||
if(result.status === 200) {
|
||||
result.json()
|
||||
.then(json => {
|
||||
if(json.json.data) {
|
||||
if(json.json.data.things) {
|
||||
let comments = json.json.data.things
|
||||
redis.setex(key, config.setexs.posts, JSON.stringify(comments), (error) => {
|
||||
if(error) {
|
||||
console.error(`Error setting the ${key} key to redis (moreComments()).`, error)
|
||||
resolve(false)
|
||||
} else {
|
||||
console.log(`Fetched the JSON from Reddit (endpoint "morechildren") for URL: ${post_url}. (moreComments())`)
|
||||
resolve(comments)
|
||||
const moreCommentsRequest = await fetch(url, redditApiGETHeaders());
|
||||
|
||||
if (moreCommentsRequest.ok) {
|
||||
let response = await moreCommentsRequest.json();
|
||||
|
||||
if (response.json.data) {
|
||||
if (response.json.data.things) {
|
||||
let comments = response.json.data.things
|
||||
await redisAsync.setex(
|
||||
key,
|
||||
config.setexs.posts,
|
||||
JSON.stringify(comments)
|
||||
);
|
||||
console.log(`Fetched more comments.`);
|
||||
|
||||
return comments;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve(false)
|
||||
}
|
||||
} else {
|
||||
resolve(false)
|
||||
console.error(
|
||||
`Something went wrong while fetching data from Reddit:
|
||||
${moreCommentsRequest.status} – ${moreCommentsRequest.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.error(`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText} (moreComments())`)
|
||||
resolve(false)
|
||||
} catch (error) {
|
||||
console.error('Error fetching more comments: ', error);
|
||||
|
||||
return null;
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(`Error fetching the JSON from Reddit (endpoint "morechildren") with url: ${url}. (moreComments())`, error)
|
||||
resolve(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
})()
|
||||
})
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processMoreComments;
|
||||
|
|
|
@ -92,13 +92,24 @@ module.exports = function() {
|
|||
obj.has_media = true
|
||||
if(!gif_to_mp4) {
|
||||
if(post.preview) {
|
||||
if(post.preview.reddit_video_preview) {
|
||||
const url = post.domain === 'i.imgur.com'
|
||||
? replaceDomains(post.url_overridden_by_dest.replace(/\.gifv$/, '.mp4'))
|
||||
: post.preview.reddit_video_preview.fallback_url;
|
||||
if(url) {
|
||||
obj.media = {
|
||||
source: await downloadAndSave(post.preview.reddit_video_preview.fallback_url),
|
||||
source: await downloadAndSave(url),
|
||||
height: post.preview.reddit_video_preview.height,
|
||||
width: post.preview.reddit_video_preview.width,
|
||||
duration: post.preview.reddit_video_preview.duration,
|
||||
is_gif: true
|
||||
}
|
||||
} else {
|
||||
obj.has_media = false
|
||||
}
|
||||
} else {
|
||||
obj.has_media = false
|
||||
}
|
||||
} else {
|
||||
obj.has_media = false
|
||||
}
|
||||
|
@ -119,12 +130,26 @@ module.exports = function() {
|
|||
*/
|
||||
if(!post_media && !has_gif && !post.gallery_data && post.url != '') {
|
||||
try {
|
||||
let u = new URL(post.url)
|
||||
let url = replaceDomains(post.url)
|
||||
const u = new URL(url)
|
||||
if(config.valid_media_domains.includes(u.hostname)) {
|
||||
let ext = u.pathname.split('.')[1]
|
||||
if(ext === 'jpg' || ext === 'png') {
|
||||
const ext = u.pathname.split('.')[1]
|
||||
if(['jpg', 'png', 'jpeg', 'gif'].includes(ext)) {
|
||||
obj.images = {
|
||||
source: await downloadAndSave(post.url)
|
||||
source: await downloadAndSave(url)
|
||||
}
|
||||
}
|
||||
else if(['gifv', 'mp4'].includes(ext)) {
|
||||
if (obj.domain === 'i.imgur.com') {
|
||||
url = url.replace(/\.gifv$/, '.mp4');
|
||||
}
|
||||
obj.has_media = true
|
||||
obj.media = {
|
||||
source: await downloadAndSave(url)
|
||||
}
|
||||
if (post.preview && post.preview.images) {
|
||||
obj.media.height = post.preview.images[0].source.height;
|
||||
obj.media.width = post.preview.images[0].source.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,58 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config');
|
||||
const link = require('./components/link')
|
||||
this.processSearchResults = (json, parsed, after, before, user_preferences) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(!parsed) {
|
||||
json = JSON.parse(json)
|
||||
}
|
||||
let posts = []
|
||||
let search_firstpage = false
|
||||
let before = json.data.before
|
||||
let after = json.data.after
|
||||
const config = require('../config');
|
||||
const link = require('./components/link');
|
||||
|
||||
if(!after && !before) {
|
||||
search_firstpage = true
|
||||
async function processSearchResults(
|
||||
json,
|
||||
parsed,
|
||||
after,
|
||||
before,
|
||||
user_preferences
|
||||
) {
|
||||
if (!parsed) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
let posts = [];
|
||||
let search_firstpage = false;
|
||||
|
||||
before = json.data.before;
|
||||
after = json.data.after;
|
||||
|
||||
if (!after && !before) {
|
||||
search_firstpage = true;
|
||||
}
|
||||
|
||||
let suggested_subreddits = false
|
||||
if(json.suggested_subreddits) {
|
||||
if(json.suggested_subreddits.data) {
|
||||
if(json.suggested_subreddits.data.children.length > 0) {
|
||||
suggested_subreddits = json.suggested_subreddits.data.children
|
||||
let suggested_subreddits = false;
|
||||
if (json.suggested_subreddits) {
|
||||
if (json.suggested_subreddits.data) {
|
||||
if (json.suggested_subreddits.data.children.length > 0) {
|
||||
suggested_subreddits = json.suggested_subreddits.data.children;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(json.data.children) {
|
||||
let view_more_posts = false
|
||||
let posts_limit = 25
|
||||
if (json.data.children) {
|
||||
let view_more_posts = false;
|
||||
let posts_limit = 25;
|
||||
|
||||
if(json.data.children.length > posts_limit) {
|
||||
view_more_posts = true
|
||||
if (json.data.children.length > posts_limit) {
|
||||
view_more_posts = true;
|
||||
} else {
|
||||
posts_limit = json.data.children.length
|
||||
posts_limit = json.data.children.length;
|
||||
}
|
||||
|
||||
for(var i = 0; i < posts_limit; i++) {
|
||||
let post = json.data.children[i].data
|
||||
for (var i = 0; i < posts_limit; i++) {
|
||||
let post = json.data.children[i].data;
|
||||
|
||||
if(post.over_18)
|
||||
if((config.nsfw_enabled === false && user_preferences.nsfw_enabled != 'true') || user_preferences.nsfw_enabled === 'false')
|
||||
continue
|
||||
if (post.over_18)
|
||||
if (
|
||||
(config.nsfw_enabled === false &&
|
||||
user_preferences.nsfw_enabled != 'true') ||
|
||||
user_preferences.nsfw_enabled === 'false'
|
||||
)
|
||||
continue;
|
||||
|
||||
let obj = await link.fromJson(post, user_preferences)
|
||||
posts.push(obj)
|
||||
let obj = await link.fromJson(post, user_preferences);
|
||||
posts.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,10 +62,9 @@ module.exports = function() {
|
|||
after: after,
|
||||
posts: posts,
|
||||
suggested_subreddits: suggested_subreddits,
|
||||
}
|
||||
};
|
||||
|
||||
resolve(obj)
|
||||
})()
|
||||
})
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
module.exports = processSearchResults;
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config')
|
||||
this.processSubredditAbout = (subreddit, redis, fetch, RedditAPI) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(subreddit && !subreddit.includes('+') && subreddit !== 'all') {
|
||||
function returnRelevantKeys(json) {
|
||||
const config = require('../config');
|
||||
const { redisAsync } = require('./redis');
|
||||
|
||||
function returnRelevantKeys(json) {
|
||||
return {
|
||||
title: json.data.title,
|
||||
public_description_html: json.data.public_description_html,
|
||||
|
@ -13,94 +10,69 @@ module.exports = function() {
|
|||
created_utc: json.data.created_utc,
|
||||
over18: json.data.over18,
|
||||
description_html: json.data.description_html,
|
||||
moderators: json.moderators
|
||||
}
|
||||
moderators: json.moderators,
|
||||
};
|
||||
}
|
||||
|
||||
async function processSubredditAbout(subreddit, redis, fetch, RedditAPI) {
|
||||
if (subreddit && !subreddit.includes('+') && subreddit !== 'all') {
|
||||
const key = `${subreddit}:sidebar`;
|
||||
|
||||
try {
|
||||
const cached = await redisAsync.get(key);
|
||||
|
||||
if (cached !== null) {
|
||||
return returnRelevantKeys(JSON.parse(cached));
|
||||
}
|
||||
|
||||
let key = `${subreddit}:sidebar`
|
||||
redis.get(key, (error, json) => {
|
||||
if(error) {
|
||||
console.error(`Error getting the ${subreddit}:sidebar key from redis.`, error)
|
||||
resolve(null)
|
||||
}
|
||||
if(json) {
|
||||
json = JSON.parse(json)
|
||||
resolve(returnRelevantKeys(json))
|
||||
} else {
|
||||
let url = `https://reddit.com/r/${subreddit}/about.json`
|
||||
if(config.use_reddit_oauth) {
|
||||
url = `https://oauth.reddit.com/r/${subreddit}/about`
|
||||
}
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
.then(result => {
|
||||
if(result.status === 200) {
|
||||
result.json()
|
||||
.then(json => {
|
||||
json.moderators = []
|
||||
redis.setex(key, config.setexs.sidebar, JSON.stringify(json), (error) => {
|
||||
if(error) {
|
||||
console.error('Error setting the sidebar key to redis.', error)
|
||||
return res.render('index', { json: null, user_preferences: req.cookies })
|
||||
} else {
|
||||
console.log('Fetched the sidebar from reddit API.')
|
||||
let moderators_url = `https://reddit.com/r/${subreddit}/about/moderators.json`
|
||||
if(config.use_reddit_oauth) {
|
||||
moderators_url = `https://oauth.reddit.com/r/${subreddit}/about/moderators`
|
||||
}
|
||||
resolve(returnRelevantKeys(json))
|
||||
/*
|
||||
* The following code is commented out because Reddit doesn't
|
||||
* anymore support fetching moderators for subreddits
|
||||
* when not logged in.
|
||||
* This might change in the future though.
|
||||
* https://codeberg.org/teddit/teddit/issues/207
|
||||
*/
|
||||
let url = `https://reddit.com/r/${subreddit}/about.json`;
|
||||
|
||||
/*
|
||||
fetch(encodeURI(moderators_url), redditApiGETHeaders())
|
||||
.then(mod_result => {
|
||||
if(mod_result.status === 200) {
|
||||
mod_result.json()
|
||||
.then(mod_json => {
|
||||
json.moderators = mod_json
|
||||
redis.setex(key, config.setexs.sidebar, JSON.stringify(json), (error) => {
|
||||
if(error) {
|
||||
console.error('Error setting the sidebar with moderators key to redis.', error)
|
||||
return res.render('index', { json: null, user_preferences: req.cookies })
|
||||
if (config.use_reddit_oauth) {
|
||||
url = `https://oauth.reddit.com/r/${subreddit}/about`;
|
||||
}
|
||||
|
||||
const subredditAboutRequest = await fetch(url, redditApiGETHeaders());
|
||||
|
||||
if (subredditAboutRequest.ok) {
|
||||
let response = await subredditAboutRequest.json();
|
||||
response.moderators = [];
|
||||
|
||||
await redisAsync.setex(
|
||||
key,
|
||||
config.setexs.sidebar,
|
||||
JSON.stringify(response)
|
||||
);
|
||||
|
||||
console.log(`Fetched sidebar for ${subreddit} from reddit API`);
|
||||
|
||||
return returnRelevantKeys(response);
|
||||
} else {
|
||||
console.log('Fetched the moderators from reddit API.')
|
||||
resolve(returnRelevantKeys(json))
|
||||
console.error(
|
||||
`Something went wrong while fetching data from reddit API:
|
||||
${subredditAboutRequest.status} – ${subredditAboutRequest.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching the sidebar: ', error);
|
||||
|
||||
return null;
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.error(`Something went wrong while fetching moderators data from reddit API. ${mod_result.status} – ${mod_result.statusText}`)
|
||||
console.error(config.reddit_api_error_text)
|
||||
resolve(returnRelevantKeys(json))
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('Error fetching moderators.', error)
|
||||
resolve(returnRelevantKeys(json))
|
||||
})
|
||||
*/
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.error(`Something went wrong while fetching data from reddit API. ${result.status} – ${result.statusText}`)
|
||||
console.error(config.reddit_api_error_text)
|
||||
resolve(null)
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('Error fetching the sidebar.', error)
|
||||
resolve(null)
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
})()
|
||||
})
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function processJsonSubredditAbout(json, parsed) {
|
||||
if (!parsed) {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
|
||||
return returnRelevantKeys(json);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processSubredditAbout,
|
||||
processJsonSubredditAbout
|
||||
};
|
||||
|
|
|
@ -1,33 +1,40 @@
|
|||
module.exports = function() {
|
||||
const config = require('../config');
|
||||
this.processJsonSubredditsExplore = (json, from, subreddit_front, user_preferences) => {
|
||||
return new Promise(resolve => {
|
||||
(async () => {
|
||||
if(from === 'redis') {
|
||||
json = JSON.parse(json)
|
||||
const config = require('../config');
|
||||
|
||||
async function processJsonSubredditsExplore(
|
||||
json,
|
||||
from,
|
||||
subreddit_front,
|
||||
user_preferences
|
||||
) {
|
||||
if (from === 'redis') {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
if(json.error) {
|
||||
resolve({ error: true, error_data: json })
|
||||
if (json.error) {
|
||||
return { error: true, error_data: json };
|
||||
} else {
|
||||
let before = json.data.before
|
||||
let after = json.data.after
|
||||
let before = json.data.before;
|
||||
let after = json.data.after;
|
||||
|
||||
let ret = {
|
||||
info: {
|
||||
before: before,
|
||||
after: after
|
||||
after: after,
|
||||
},
|
||||
links: []
|
||||
}
|
||||
links: [],
|
||||
};
|
||||
|
||||
let children_len = json.data.children.length
|
||||
let children_len = json.data.children.length;
|
||||
|
||||
for(var i = 0; i < children_len; i++) {
|
||||
let data = json.data.children[i].data
|
||||
for (var i = 0; i < children_len; i++) {
|
||||
let data = json.data.children[i].data;
|
||||
|
||||
if(data.over_18)
|
||||
if((config.nsfw_enabled === false && user_preferences.nsfw_enabled != 'true') || user_preferences.nsfw_enabled === 'false')
|
||||
continue
|
||||
if (data.over_18)
|
||||
if (
|
||||
(config.nsfw_enabled === false &&
|
||||
user_preferences.nsfw_enabled != 'true') ||
|
||||
user_preferences.nsfw_enabled === 'false'
|
||||
)
|
||||
continue;
|
||||
|
||||
let obj = {
|
||||
created: data.created_utc,
|
||||
|
@ -41,12 +48,11 @@ module.exports = function() {
|
|||
over_18: data.over18,
|
||||
title: data.title,
|
||||
subreddit_front: subreddit_front,
|
||||
};
|
||||
ret.links.push(obj);
|
||||
}
|
||||
ret.links.push(obj)
|
||||
}
|
||||
resolve(ret)
|
||||
}
|
||||
})()
|
||||
})
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processJsonSubredditsExplore;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
const config = require('../config');
|
||||
const { promisify } = require('util');
|
||||
const r = require('redis');
|
||||
|
||||
const redisOptions = {
|
||||
host: '127.0.0.1',
|
||||
port: 6379,
|
||||
};
|
||||
|
||||
if (config.redis_db) {
|
||||
redisOptions.db = config.redis_db;
|
||||
}
|
||||
|
||||
if (config.redis_host) {
|
||||
redisOptions.host = config.redis_host;
|
||||
}
|
||||
|
||||
if (config.redis_port && config.redis_port > 0) {
|
||||
redisOptions.port = config.redis_port;
|
||||
}
|
||||
|
||||
if (config.redis_password) {
|
||||
redisOptions.password = config.redis_password;
|
||||
}
|
||||
|
||||
// Stub Redis if disabled
|
||||
const stub = {
|
||||
get: (_, callback) => callback(null, null),
|
||||
setex: (_, _1, _2, callback) => callback(null),
|
||||
on: () => {},
|
||||
};
|
||||
|
||||
const redisDisabled = !config.redis_enabled;
|
||||
|
||||
const redis = redisDisabled ? stub : r.createClient(redisOptions);
|
||||
|
||||
const redisAsync = {
|
||||
get: promisify(redis.get).bind(redis),
|
||||
setex: promisify(redis.setex).bind(redis),
|
||||
};
|
||||
|
||||
redis.on('error', (error) => {
|
||||
if (error) {
|
||||
console.error(`Redis error: ${error}`);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
redis,
|
||||
redisAsync,
|
||||
};
|
|
@ -0,0 +1,87 @@
|
|||
const { processJsonPost, getPostItem } = require('../processJsonPost');
|
||||
|
||||
module.exports = function () {
|
||||
const config = require('../../config');
|
||||
this.handleTedditApiPost = async (
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
from,
|
||||
api_type,
|
||||
api_target
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
console.log('Teddit API request - post');
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
if (api_type === 'rss') {
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
let items = '';
|
||||
|
||||
let post = json[0].data.children[0].data;
|
||||
let comments = json[1].data.children;
|
||||
|
||||
items += await getPostItem(post, req, protocol);
|
||||
|
||||
for (var i = 0; i < comments.length; i++) {
|
||||
let comment = comments[i].data;
|
||||
let kind = comments[i].kind;
|
||||
|
||||
let title = `/u/${comment.author} on ${post.title}`;
|
||||
|
||||
comment.permalink = `${protocol}://${config.domain}${comment.permalink}`;
|
||||
|
||||
if (kind !== 'more') {
|
||||
items += `
|
||||
<item>
|
||||
<title>${title}</title>
|
||||
<author>${comment.author}</author>
|
||||
<created>${comment.created}</created>
|
||||
<pubDate>${new Date(
|
||||
comment.created_utc * 1000
|
||||
).toGMTString()}</pubDate>
|
||||
<id>${comment.id}</id>
|
||||
<link>${comment.permalink}</link>
|
||||
<description><![CDATA[${unescape(
|
||||
comment.body_html
|
||||
)}]]></description>
|
||||
<ups>${comment.ups}</ups>
|
||||
</item>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
let xml_output = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
|
||||
<channel>
|
||||
<atom:link href="${post.permalink}?api&type=rss" rel="self" type="application/rss+xml" />
|
||||
<title>${post.title}</title>
|
||||
<link>${post.url}</link>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>`;
|
||||
res.setHeader('Content-Type', 'application/rss+xml');
|
||||
return res.end(xml_output);
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let processed_json = await processJsonPost(
|
||||
json,
|
||||
true,
|
||||
req.cookies
|
||||
);
|
||||
|
||||
return res.end(JSON.stringify(processed_json));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,114 +1,52 @@
|
|||
module.exports = function() {
|
||||
const config = require('../../config')
|
||||
this.handleTedditApiSubreddit = async (json, req, res, from, api_type, api_target, subreddit) => {
|
||||
if(!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
let msg = { info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.' }
|
||||
return res.end(JSON.stringify(msg))
|
||||
const processJsonSubreddit = require('../processJsonSubreddit');
|
||||
const { processJsonSubredditAbout } = require('../processSubredditAbout');
|
||||
const processSearchResults = require('../processSearchResults.js');
|
||||
const { processJsonPostList, getPostItem } = require('../processJsonPost');
|
||||
const processJsonSubredditsExplore = require('../processSubredditsExplore.js');
|
||||
|
||||
module.exports = function () {
|
||||
const config = require('../../config');
|
||||
this.handleTedditApiSubreddit = async (
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
from,
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit,
|
||||
mode
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
console.log('Teddit API request - subreddit')
|
||||
let _json = json // Keep the original json
|
||||
if(from === 'redis')
|
||||
json = JSON.parse(json)
|
||||
console.log('Teddit API request - subreddit');
|
||||
let _json = json; // Keep the original json
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
if(api_type === 'rss') {
|
||||
let protocol = (config.https_enabled ? 'https' : 'http')
|
||||
let items = ''
|
||||
for(var i = 0; i < json.data.children.length; i++) {
|
||||
let link = json.data.children[i].data
|
||||
let thumbnail = ''
|
||||
let post_image = ''
|
||||
let is_self_link = false
|
||||
let valid_reddit_self_domains = ['reddit.com']
|
||||
if (api_type === 'rss') {
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
let items = '';
|
||||
|
||||
if(link.domain) {
|
||||
let tld = link.domain.split('self.')
|
||||
if(tld.length > 1) {
|
||||
if(!tld[1].includes('.')) {
|
||||
is_self_link = true
|
||||
link.url = teddifyUrl(link.url)
|
||||
}
|
||||
}
|
||||
if(config.valid_media_domains.includes(link.domain) || valid_reddit_self_domains.includes(link.domain)) {
|
||||
is_self_link = true
|
||||
link.url = teddifyUrl(link.url)
|
||||
}
|
||||
for (var i = 0; i < json.data.children.length; i++) {
|
||||
let post = json.data.children[i].data;
|
||||
items += await getPostItem(post, req, protocol);
|
||||
}
|
||||
|
||||
if(link.preview && link.thumbnail !== 'self') {
|
||||
if(!link.url.startsWith('/r/') && isGif(link.url)) {
|
||||
let s = await downloadAndSave(link.thumbnail, 'thumb_')
|
||||
thumbnail = `${protocol}://${config.domain}${s}`
|
||||
} else {
|
||||
if(link.preview.images[0].resolutions[0]) {
|
||||
let s = await downloadAndSave(link.preview.images[0].resolutions[0].url, 'thumb_')
|
||||
thumbnail = `${protocol}://${config.domain}${s}`
|
||||
if(!isGif(link.url) && !link.post_hint.includes(':video')) {
|
||||
s = await downloadAndSave(link.preview.images[0].source.url)
|
||||
post_image = `${protocol}://${config.domain}${s}`
|
||||
}
|
||||
}
|
||||
}
|
||||
let r_subreddit = '/r/' + subreddit;
|
||||
let title = r_subreddit;
|
||||
let link = `${protocol}://${config.domain}${r_subreddit}`;
|
||||
if (subreddit === '/') {
|
||||
r_subreddit = 'frontpage';
|
||||
title = 'teddit frontpage';
|
||||
link = `${protocol}://${config.domain}`;
|
||||
}
|
||||
|
||||
link.permalink = `${protocol}://${config.domain}${link.permalink}`
|
||||
|
||||
if(is_self_link)
|
||||
link.url = link.permalink
|
||||
|
||||
if(req.query.hasOwnProperty('full_thumbs')) {
|
||||
if(!post_image)
|
||||
post_image = thumbnail
|
||||
|
||||
thumbnail = post_image
|
||||
}
|
||||
|
||||
let enclosure = ''
|
||||
if(thumbnail != '') {
|
||||
let mime = ''
|
||||
let ext = thumbnail.split('.').pop()
|
||||
if(ext === 'png')
|
||||
mime = 'image/png'
|
||||
else
|
||||
mime = 'image/jpeg'
|
||||
enclosure = `<enclosure length="0" type="${mime}" url="${thumbnail}" />`
|
||||
}
|
||||
|
||||
let append_desc_html = `<br/><a href="${link.url}">[link]</a> <a href="${link.permalink}">[comments]</a>`
|
||||
|
||||
items += `
|
||||
<item>
|
||||
<title>${link.title}</title>
|
||||
<author>${link.author}</author>
|
||||
<created>${link.created}</created>
|
||||
<pubDate>${new Date(link.created_utc*1000).toGMTString()}</pubDate>
|
||||
<domain>${link.domain}</domain>
|
||||
<id>${link.id}</id>
|
||||
<thumbnail>${thumbnail}</thumbnail>
|
||||
${enclosure}
|
||||
<link>${link.permalink}</link>
|
||||
<url>${link.url}</url>
|
||||
<description><![CDATA[${unescape(link.selftext_html)}${append_desc_html}]]></description>
|
||||
<num_comments>${link.num_comments}</num_comments>
|
||||
<ups>${link.ups}</ups>
|
||||
<stickied>${link.stickied}</stickied>
|
||||
<is_self_link>${is_self_link}</is_self_link>
|
||||
</item>
|
||||
`
|
||||
}
|
||||
|
||||
let r_subreddit = '/r/' + subreddit
|
||||
let title = r_subreddit
|
||||
let link = `${protocol}://${config.domain}${r_subreddit}`
|
||||
if(subreddit === '/') {
|
||||
r_subreddit = 'frontpage'
|
||||
title = 'teddit frontpage'
|
||||
link = `${protocol}://${config.domain}`
|
||||
}
|
||||
|
||||
let xml_output =
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
let xml_output = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
|
||||
<channel>
|
||||
<atom:link href="${link}/?api&type=rss" rel="self" type="application/rss+xml" />
|
||||
|
@ -117,50 +55,203 @@ module.exports = function() {
|
|||
<description>Subreddit feed for: ${r_subreddit}</description>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>`
|
||||
res.setHeader('Content-Type', 'application/rss+xml')
|
||||
return res.end(xml_output)
|
||||
</rss>`;
|
||||
res.setHeader('Content-Type', 'application/rss+xml');
|
||||
return res.end(xml_output);
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
if(api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json))
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(_json, from, null, req.cookies)
|
||||
let processed_json = await processJsonSubreddit(
|
||||
_json,
|
||||
from,
|
||||
null,
|
||||
req.cookies
|
||||
);
|
||||
|
||||
let protocol = (config.https_enabled ? 'https' : 'http')
|
||||
for(var i = 0; i < processed_json.links.length; i++) {
|
||||
let link = processed_json.links[i]
|
||||
let valid_reddit_self_domains = ['reddit.com']
|
||||
let is_self_link = false
|
||||
await processJsonPostList(processed_json.links, mode);
|
||||
|
||||
if(link.domain) {
|
||||
let tld = link.domain.split('self.')
|
||||
if(tld.length > 1) {
|
||||
if(!tld[1].includes('.')) {
|
||||
is_self_link = true
|
||||
link.url = teddifyUrl(link.url)
|
||||
return res.end(JSON.stringify(processed_json));
|
||||
}
|
||||
}
|
||||
if(config.valid_media_domains.includes(link.domain) || valid_reddit_self_domains.includes(link.domain)) {
|
||||
is_self_link = true
|
||||
link.url = teddifyUrl(link.url)
|
||||
}
|
||||
};
|
||||
this.handleTedditApiSubredditAbout = async (
|
||||
json,
|
||||
res,
|
||||
from,
|
||||
api_target
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
link.permalink = `${protocol}://${config.domain}${link.permalink}`
|
||||
console.log('Teddit API request - subreddit about');
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
if(is_self_link)
|
||||
link.url = link.permalink
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
|
||||
if(link.images) {
|
||||
if(link.images.thumb !== 'self') {
|
||||
link.images.thumb = `${protocol}://${config.domain}${link.images.thumb}`
|
||||
}
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let subreddit_about = await processJsonSubredditAbout(
|
||||
json,
|
||||
true
|
||||
);
|
||||
|
||||
return res.end(JSON.stringify(subreddit_about));
|
||||
}
|
||||
};
|
||||
this.handleTedditApiSubredditSearch = async (
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
from,
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit,
|
||||
query,
|
||||
mode
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
return res.end(JSON.stringify(processed_json))
|
||||
console.log('Teddit API request - subreddit search');
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
if (api_type === 'rss') {
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
let items = '';
|
||||
|
||||
for (var i = 0; i < json.data.children.length; i++) {
|
||||
let post = json.data.children[i].data;
|
||||
items += await getPostItem(post, req, protocol);
|
||||
}
|
||||
|
||||
let r_subreddit = '/r/' + subreddit;
|
||||
let title = `${query} - ${r_subreddit}`;
|
||||
let link = `${protocol}://${config.domain}${r_subreddit}/search?q=${query}`;
|
||||
|
||||
let xml_output = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
|
||||
<channel>
|
||||
<atom:link href="${link}&api&type=rss" rel="self" type="application/rss+xml" />
|
||||
<title>${title}</title>
|
||||
<link>${link}</link>
|
||||
<description>Results for: ${query} - ${r_subreddit}</description>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>`;
|
||||
|
||||
res.setHeader('Content-Type', 'application/rss+xml');
|
||||
|
||||
return res.end(xml_output);
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let processed_json = await processSearchResults(
|
||||
json,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
req.cookies
|
||||
);
|
||||
|
||||
await processJsonPostList(processed_json.posts, mode);
|
||||
|
||||
return res.end(JSON.stringify(processed_json));
|
||||
}
|
||||
}
|
||||
};
|
||||
this.handleTedditApiSubredditsExplore = async (
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
from,
|
||||
api_type,
|
||||
api_target,
|
||||
query
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Teddit API request - subreddit explore');
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
if (api_type === 'rss') {
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
let items = '';
|
||||
|
||||
let children_len = json.data.children.length;
|
||||
|
||||
for (var i = 0; i < children_len; i++) {
|
||||
let data = json.data.children[i].data;
|
||||
|
||||
items += `
|
||||
<item>
|
||||
<title>${data.title}</title>
|
||||
<created>${data.created}</created>
|
||||
<pubDate>${new Date(
|
||||
data.created_utc * 1000
|
||||
).toGMTString()}</pubDate>
|
||||
<id>${data.id}</id>
|
||||
<name>${data.display_name}</name>
|
||||
<name_prefixed>${data.display_name_prefixed}</name_prefixed>
|
||||
<url>${replaceDomains(data.url, req.cookies)}</url>
|
||||
<description><![CDATA[${unescape(
|
||||
data.public_description_html
|
||||
)}]]></description>
|
||||
<subscribers>${data.subscribers}</subscribers>
|
||||
<over_18>${data.over18}</over_18>
|
||||
</item>
|
||||
`;
|
||||
}
|
||||
|
||||
let title = `${query}`;
|
||||
let link = `${protocol}://${config.domain}/subreddits/search?q=${query}`;
|
||||
|
||||
let xml_output = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
|
||||
<channel>
|
||||
<atom:link href="${link}&api&type=rss" rel="self" type="application/rss+xml" />
|
||||
<title>${title}</title>
|
||||
<link>${link}</link>
|
||||
<description>Results for: ${query}</description>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>`;
|
||||
res.setHeader('Content-Type', 'application/rss+xml');
|
||||
return res.end(xml_output);
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let processed_json = await processJsonSubredditsExplore(
|
||||
json,
|
||||
true,
|
||||
null,
|
||||
req.cookies
|
||||
);
|
||||
|
||||
return res.end(JSON.stringify(processed_json));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,73 +1,85 @@
|
|||
module.exports = function() {
|
||||
const config = require('../../config')
|
||||
this.handleTedditApiUser = async (json, req, res, from, api_type, api_target, user) => {
|
||||
if(!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
let msg = { info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.' }
|
||||
return res.end(JSON.stringify(msg))
|
||||
const processJsonUser = require('../processJsonUser');
|
||||
|
||||
module.exports = function () {
|
||||
const config = require('../../config');
|
||||
this.handleTedditApiUser = async (
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
from,
|
||||
api_type,
|
||||
api_target,
|
||||
user
|
||||
) => {
|
||||
if (!config.api_enabled) {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
let msg = {
|
||||
info: 'This instance do not support API requests. Please see https://codeberg.org/teddit/teddit#instances for instances that support API, or setup your own instance.',
|
||||
};
|
||||
return res.end(JSON.stringify(msg));
|
||||
}
|
||||
|
||||
console.log('Teddit API request - user')
|
||||
let _json = json // Keep the original json
|
||||
if(from === 'redis')
|
||||
json = JSON.parse(json)
|
||||
console.log('Teddit API request - user');
|
||||
let _json = json; // Keep the original json
|
||||
if (from === 'redis') json = JSON.parse(json);
|
||||
|
||||
let protocol = (config.https_enabled ? 'https' : 'http')
|
||||
let link = `${protocol}://${config.domain}/user/${user}`
|
||||
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
|
||||
let link = `${protocol}://${config.domain}/user/${user}`;
|
||||
|
||||
if(api_type === 'rss') {
|
||||
let items = ''
|
||||
let posts_limit = 25
|
||||
if (api_type === 'rss') {
|
||||
let items = '';
|
||||
let posts_limit = 25;
|
||||
|
||||
if(json.overview.data.children.length <= posts_limit) {
|
||||
posts_limit = json.overview.data.children.length
|
||||
if (json.overview.data.children.length <= posts_limit) {
|
||||
posts_limit = json.overview.data.children.length;
|
||||
}
|
||||
|
||||
for(var i = 0; i < posts_limit; i++) {
|
||||
let post = json.overview.data.children[i].data
|
||||
let post_id = post.permalink.split('/').slice(-2)[0] + '/'
|
||||
let url = post.permalink.replace(post_id, '')
|
||||
let permalink = `${protocol}://${config.domain}${post.permalink}`
|
||||
let comments_url = `${protocol}://${config.domain}${url}`
|
||||
let kind = json.overview.data.children[i].kind
|
||||
for (var i = 0; i < posts_limit; i++) {
|
||||
let post = json.overview.data.children[i].data;
|
||||
let post_id = post.permalink.split('/').slice(-2)[0] + '/';
|
||||
let url = post.permalink.replace(post_id, '');
|
||||
let permalink = `${protocol}://${config.domain}${post.permalink}`;
|
||||
let comments_url = `${protocol}://${config.domain}${url}`;
|
||||
let kind = json.overview.data.children[i].kind;
|
||||
|
||||
let t1_elements = ''
|
||||
let t3_elements = ''
|
||||
if(kind === 't1') {
|
||||
let append_desc_html = `<br/><a href="${permalink}">[link]</a> <a href="${comments_url}">[comments]</a>`
|
||||
let t1_elements = '';
|
||||
let t3_elements = '';
|
||||
if (kind === 't1') {
|
||||
let append_desc_html = `<br/><a href="${permalink}">[link]</a> <a href="${comments_url}">[comments]</a>`;
|
||||
t1_elements = `
|
||||
<description><![CDATA[${unescape(post.body_html)}${append_desc_html}]]></description>
|
||||
<description><![CDATA[${unescape(
|
||||
post.body_html
|
||||
)}${append_desc_html}]]></description>
|
||||
<url>${comments_url}</url>
|
||||
`
|
||||
`;
|
||||
}
|
||||
if(kind === 't3') {
|
||||
let s = await downloadAndSave(post.thumbnail, 'thumb_')
|
||||
let thumbnail = ''
|
||||
let enclosure = ''
|
||||
if(s !== 'self' && s != '') {
|
||||
let img = `${protocol}://${config.domain}${s}`
|
||||
thumbnail = `<thumbnail>${img}</thumbnail>`
|
||||
if (kind === 't3') {
|
||||
let s = await downloadAndSave(post.thumbnail, 'thumb_');
|
||||
let thumbnail = '';
|
||||
let enclosure = '';
|
||||
if (s !== 'self' && s != '') {
|
||||
let img = `${protocol}://${config.domain}${s}`;
|
||||
thumbnail = `<thumbnail>${img}</thumbnail>`;
|
||||
|
||||
let mime = ''
|
||||
let ext = s.split('.').pop()
|
||||
if(ext === 'png')
|
||||
mime = 'image/png'
|
||||
else
|
||||
mime = 'image/jpeg'
|
||||
enclosure = `<enclosure length="0" type="${mime}" url="${img}" />`
|
||||
let mime = '';
|
||||
let ext = s.split('.').pop();
|
||||
if (ext === 'png') mime = 'image/png';
|
||||
else mime = 'image/jpeg';
|
||||
enclosure = `<enclosure length="0" type="${mime}" url="${img}" />`;
|
||||
}
|
||||
let append_desc_html = `submitted by <a href="${protocol}://${config.domain}/u/${user}>/u/${user}</a> to <a href="${protocol}://${config.domain}/r/${post.subreddit}/">r/${post.subreddit}</a>`
|
||||
append_desc_html += `<br/><a href="${permalink}">[comments]</a>`
|
||||
let append_desc_html = `submitted by <a href="${protocol}://${config.domain}/u/${user}>/u/${user}</a> to <a href="${protocol}://${config.domain}/r/${post.subreddit}/">r/${post.subreddit}</a>`;
|
||||
append_desc_html += `<br/><a href="${permalink}">[comments]</a>`;
|
||||
t3_elements = `
|
||||
<description><![CDATA[${unescape(post.selftext_html)}${append_desc_html}]]></description>
|
||||
<description><![CDATA[${unescape(
|
||||
post.selftext_html
|
||||
)}${append_desc_html}]]></description>
|
||||
${thumbnail}
|
||||
${enclosure}
|
||||
`
|
||||
`;
|
||||
}
|
||||
|
||||
let title = post.title
|
||||
if(!post.title)
|
||||
title = post.link_title
|
||||
let title = post.title;
|
||||
if (!post.title) title = post.link_title;
|
||||
|
||||
items += `
|
||||
<item>
|
||||
|
@ -76,7 +88,9 @@ module.exports = function() {
|
|||
<kind>${kind}</kind>
|
||||
<subreddit>${post.subreddit}</subreddit>
|
||||
<created>${post.created_utc}</created>
|
||||
<pubDate>${new Date(post.created_utc*1000).toGMTString()}</pubDate>
|
||||
<pubDate>${new Date(
|
||||
post.created_utc * 1000
|
||||
).toGMTString()}</pubDate>
|
||||
<ups>${post.ups}</ups>
|
||||
<link>${permalink}</link>
|
||||
<edited>${post.edited}</edited>
|
||||
|
@ -85,11 +99,10 @@ module.exports = function() {
|
|||
${t1_elements}
|
||||
${t3_elements}
|
||||
</item>
|
||||
`
|
||||
`;
|
||||
}
|
||||
|
||||
let xml_output =
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
let xml_output = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
|
||||
<channel>
|
||||
<atom:link href="${link}/?api&type=rss" rel="self" type="application/rss+xml" />
|
||||
|
@ -97,17 +110,23 @@ module.exports = function() {
|
|||
<link>${link}</link>
|
||||
${items}
|
||||
</channel>
|
||||
</rss>`
|
||||
res.setHeader('Content-Type', 'application/rss+xml')
|
||||
return res.end(xml_output)
|
||||
</rss>`;
|
||||
res.setHeader('Content-Type', 'application/rss+xml');
|
||||
return res.end(xml_output);
|
||||
} else {
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
if(api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json))
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
if (api_target === 'reddit') {
|
||||
return res.end(JSON.stringify(json));
|
||||
} else {
|
||||
let processed_json = await processJsonUser(json, true, null, null, req.cookies)
|
||||
return res.end(JSON.stringify(processed_json))
|
||||
let processed_json = await processJsonUser(
|
||||
json,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
req.cookies
|
||||
);
|
||||
return res.end(JSON.stringify(processed_json));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
[
|
||||
{
|
||||
"url": "https://teddit.net"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.ggc-project.de"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.zaggy.nl"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.tinfoil-hat.net"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.domain.glass"
|
||||
},
|
||||
{
|
||||
"url": "https://snoo.ioens.is",
|
||||
"onion": "http://snoo.ioensistjs7wd746zluwixvojbbkxhr37lepdvwtdfeav673o64iflqd.onion"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.httpjames.space"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.xbdm.fun"
|
||||
},
|
||||
{
|
||||
"url": "",
|
||||
"onion": "http://ibarajztopxnuhabfu7fg6gbudynxofbnmvis3ltj6lfx47b6fhrd5qd.onion",
|
||||
"i2p": "http://xugoqcf2pftm76vbznx4xuhrzyb5b6zwpizpnw2hysexjdn5l2tq.b32.i2p",
|
||||
"notes": "Operated by mdleom.com"
|
||||
},
|
||||
{
|
||||
"url": "https://incogsnoo.com",
|
||||
"onion": "http://tedditfyn6idalzso5wam5qd3kdtxoljjhbrbbx34q2xkcisvshuytad.onion",
|
||||
"i2p": "http://teddit.i2p"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.pussthecat.org",
|
||||
"notes": "Operated by PussTheCat.org"
|
||||
},
|
||||
{
|
||||
"url": "https://reddit.lol",
|
||||
"onion": "http://dawtyi5e2cfyfmoht4izmczi42aa2zwh6wi34zwvc6rzf2acpxhrcrad.onion",
|
||||
"i2p": "http://vzeiwzi7ogwl3ijrfek4fbtwhvamxcpyqoc3s4vcgnhlp54s5clq.b32.i2p",
|
||||
"notes": "Operated by https://liberta.casa"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.sethforprivacy.com",
|
||||
"onion": "http://qtpvyiaqhmwccxwzsqubd23xhmmrt75tdyw35kp43w4hvamsgl3x27ad.onion",
|
||||
"notes": "For more similar hosted tools, see blog.sethforprivacy.com"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.adminforge.de",
|
||||
"notes": "Operated by https://adminforge.de"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.bus-hit.me",
|
||||
"notes": "Operated by https://bus-hit.me"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.froth.zone"
|
||||
},
|
||||
{
|
||||
"url": "https://rdt.trom.tf/",
|
||||
"notes": "Part of the https://trom.tf/ project"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.encrypted-data.xyz"
|
||||
},
|
||||
{
|
||||
"url": "https://i.opnxng.com"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.tokhmi.xyz"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.garudalinux.org",
|
||||
"notes": "Managed by https://garudalinux.org"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.privacytools.io",
|
||||
"onion": "http://jnuonmf2n36sfdmyksqqqyab3w63cq4kx24olyjleh5z6zzfvyt7uqqd.onion",
|
||||
"notes": "Part of: https://www.privacytools.io"
|
||||
},
|
||||
{
|
||||
"url": "https://td.vern.cc",
|
||||
"onion": "http://td.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion",
|
||||
"i2p": "http://verncco2oaxjikammz4pi7umzp673cme6zuemx7yeeewspwrw3va.b32.i2p",
|
||||
"notes": "Operated by https://vern.cc"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.rawbit.ninja",
|
||||
"onion": "http://yqu4yj5lju7bmlwpzpmltb5gsu6cw7nnbcxxx4iqemwa56nxjiggf4qd.onion",
|
||||
"notes": "Operated by https://rawbit.ninja"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.hostux.net",
|
||||
"notes": "Managed by https://hostux.net"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.no-logs.com/",
|
||||
"notes": "Managed by https://no-logs.com"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.projectsegfau.lt",
|
||||
"onion": "http://teddit.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion",
|
||||
"notes": "Maintained by Project Segfault Team (https://projectsegfau.lt/team)"
|
||||
},
|
||||
{
|
||||
"url": "https://teddit.laserdisc.tokyo"
|
||||
},
|
||||
{
|
||||
"url": "https://t.sneed.network",
|
||||
"onion": "http://t.sneed4fmhevap3ci4xhf4wgkf72lwk275lcgomnfgwniwmqvaxyluuid.onion/",
|
||||
"notes": "Operated by sneednet (https://sneed.network)"
|
||||
},
|
||||
{
|
||||
"onion": "http://teddit.skunky7dhv7nohsoalpwe3sxfz3fbkad7r3wk632riye25vqm3meqead.onion/",
|
||||
"notes": "Self-hosted, works only from 7-11 AM Moscow time to 10-12 PM, in Donetsk"
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "teddit",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.9",
|
||||
"description": "A free and open source alternative Reddit front-end focused on privacy.",
|
||||
"homepage": "https://teddit.net",
|
||||
"bugs": {
|
||||
|
@ -20,19 +20,22 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node app.js"
|
||||
"start": "node app.js",
|
||||
"dev": "nodemon app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"express": "^4.17.1",
|
||||
"express": "^4.18.2",
|
||||
"helmet": "^4.6.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"minizlib": "^2.1.2",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-fetch": "^2.6.5",
|
||||
"postman-request": "^2.88.1-postman.30",
|
||||
"pug": "^3.0.2",
|
||||
"redis": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {}
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,25 @@ const config = require('../config');
|
|||
const { redis, fetch } = require('../app');
|
||||
const homeRoute = require('express').Router();
|
||||
|
||||
const processUser = require('../inc/processJsonUser.js')();
|
||||
const processPost = require('../inc/processJsonPost.js')();
|
||||
const processAbout = require('../inc/processSubredditAbout.js')();
|
||||
const tedditApiUser = require('../inc/teddit_api/handleUser.js')();
|
||||
const processSearches = require('../inc/processSearchResults.js')();
|
||||
const processSubreddit = require('../inc/processJsonSubreddit.js')();
|
||||
const processJsonSubreddit = require('../inc/processJsonSubreddit.js');
|
||||
const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')();
|
||||
const processMoreComments = require('../inc/processMoreComments.js')();
|
||||
const processSubredditsExplore =
|
||||
require('../inc/processSubredditsExplore.js')();
|
||||
|
||||
homeRoute.get('/:sort?', async (req, res, next) => {
|
||||
homeRoute.get('/', (req, res, next) => {
|
||||
if (
|
||||
(config.clean_homepage && req.cookies.prefer_frontpage !== 'true') ||
|
||||
(!config.clean_homepage && req.cookies.prefer_frontpage == 'undefined')
|
||||
) {
|
||||
return res.render('homepage', {
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
homeRoute.get([`/:sort?`, '/frontpage'], async (req, res, next) => {
|
||||
let past = req.query.t;
|
||||
let before = req.query.before;
|
||||
let after = req.query.after;
|
||||
|
@ -25,26 +32,61 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
let proxyable =
|
||||
sortby.includes('.jpg') ||
|
||||
sortby.includes('.png') ||
|
||||
sortby.includes('.jpeg')
|
||||
sortby.includes('.jpeg') ||
|
||||
sortby.includes('.mp4') ||
|
||||
sortby.includes('.gif') ||
|
||||
sortby.includes('.gifv')
|
||||
? true
|
||||
: false;
|
||||
if (proxyable) {
|
||||
let media_url = '';
|
||||
const replacable_media_domains = ['i.redd.it', 'v.redd.it', 'external-preview.redd.it', 'preview.redd.it']
|
||||
if (req.query.teddit_proxy) {
|
||||
if (replacable_media_domains.includes(req.query.teddit_proxy)) {
|
||||
let full_url = req.protocol + '://' + req.get('host') + req.originalUrl;
|
||||
let u = new URL(full_url);
|
||||
let filename = u.pathname || '';
|
||||
let query = u.search || '';
|
||||
if (query != '') {
|
||||
let params = new URLSearchParams(query);
|
||||
params.delete('teddit_proxy');
|
||||
query = '?' + params.toString();
|
||||
}
|
||||
media_url = `https://${req.query.teddit_proxy}${filename}${query}`;
|
||||
}
|
||||
} else {
|
||||
let params = new URLSearchParams(req.query).toString();
|
||||
let image_url = `https://preview.redd.it/${sortby}?${params}`;
|
||||
let proxied_image = await downloadAndSave(image_url);
|
||||
if (proxied_image) {
|
||||
return res.redirect(proxied_image);
|
||||
media_url = `https://preview.redd.it/${sortby}?${params}`;
|
||||
if (media_url.includes('teddit_proxy')) {
|
||||
// if the URL includes teddit_proxy query param, remove everything after it
|
||||
media_url = media_url.split('%3Fteddit_proxy')[0];
|
||||
}
|
||||
}
|
||||
|
||||
let proxied_media = await downloadAndSave(media_url);
|
||||
if (proxied_media) {
|
||||
return res.redirect(proxied_media);
|
||||
} else {
|
||||
return res.redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
let is_comment =
|
||||
(sortby.length == 6 || sortby.length == 7) &&
|
||||
sortby != "rising"
|
||||
? true
|
||||
: false;
|
||||
|
||||
if (is_comment) {
|
||||
return res.redirect('/comments/' + sortby);
|
||||
}
|
||||
|
||||
let d = `&after=${after}`;
|
||||
if (before) {
|
||||
d = `&before=${before}`;
|
||||
}
|
||||
|
||||
if (sortby == '') {
|
||||
if (sortby == '' || sortby == 'frontpage') {
|
||||
sortby = 'hot';
|
||||
}
|
||||
|
||||
|
@ -99,9 +141,10 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error('Error getting the frontpage key from redis.', error);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -115,7 +158,8 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
'redis',
|
||||
api_type,
|
||||
api_target,
|
||||
'/'
|
||||
'/',
|
||||
'full'
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -124,12 +168,13 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
null,
|
||||
req.cookies
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: processed_json,
|
||||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
redis_key: key,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -160,9 +205,10 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
'Error setting the frontpage key to redis.',
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log('Fetched the frontpage from Reddit.');
|
||||
|
@ -175,7 +221,8 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
'from_online',
|
||||
api_type,
|
||||
api_target,
|
||||
'/'
|
||||
'/',
|
||||
'full'
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -184,12 +231,13 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
null,
|
||||
req.cookies
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: processed_json,
|
||||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
redis_key: key,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -202,10 +250,11 @@ homeRoute.get('/:sort?', async (req, res, next) => {
|
|||
`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -68,6 +68,10 @@ overridingRoutes.all('*', (req, res, next) => {
|
|||
maxAge: 31536000,
|
||||
httpOnly: true,
|
||||
});
|
||||
} else if (!req.cookies.show_upvoted_percentage) {
|
||||
if (config.show_upvoted_percentage) {
|
||||
req.cookies.show_upvoted_percentage = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
let domainTwitter = req.query.domain_twitter;
|
||||
|
@ -97,6 +101,24 @@ overridingRoutes.all('*', (req, res, next) => {
|
|||
});
|
||||
}
|
||||
|
||||
let domainQuora = req.query.domain_quora;
|
||||
if (domainQuora) {
|
||||
req.cookies.domain_quora = domainQuora;
|
||||
res.cookie('domain_quora', domainQuora, {
|
||||
maxAge: 31536000,
|
||||
httpOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
let domainImgur = req.query.domain_imgur;
|
||||
if (domainImgur) {
|
||||
req.cookies.domain_imgur = domainImgur;
|
||||
res.cookie('domain_imgur', domainImgur, {
|
||||
maxAge: 31536000,
|
||||
httpOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
let videosMuted = req.query.videos_muted;
|
||||
if (videosMuted) {
|
||||
req.cookies.videos_muted = videosMuted;
|
||||
|
|
|
@ -10,17 +10,24 @@ function resetPreferences(res) {
|
|||
res.clearCookie('post_media_max_height');
|
||||
res.clearCookie('collapse_child_comments');
|
||||
res.clearCookie('show_upvoted_percentage');
|
||||
res.clearCookie('show_upvotes')
|
||||
res.clearCookie('subbed_subreddits');
|
||||
res.clearCookie('domain_twitter');
|
||||
res.clearCookie('domain_youtube');
|
||||
res.clearCookie('domain_instagram');
|
||||
res.clearCookie('domain_quora');
|
||||
res.clearCookie('domain_imgur');
|
||||
res.clearCookie('videos_muted');
|
||||
res.clearCookie('prefer_frontpage');
|
||||
res.clearCookie('show_large_gallery_images');
|
||||
res.clearCookie('default_comment_sort');
|
||||
}
|
||||
|
||||
preferenceRoutes.get('/preferences', (req, res, next) => {
|
||||
return res.render('preferences', {
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
comment_sort_values: ['best', 'top', 'new', 'controversial', 'old', 'qa'],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -41,9 +48,10 @@ preferenceRoutes.get('/import_prefs/:key', (req, res, next) => {
|
|||
`Error getting the preferences import key ${key} from redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -82,10 +90,16 @@ preferenceRoutes.post('/saveprefs', (req, res, next) => {
|
|||
let post_media_max_height = req.body.post_media_max_height;
|
||||
let collapse_child_comments = req.body.collapse_child_comments;
|
||||
let show_upvoted_percentage = req.body.show_upvoted_percentage;
|
||||
let show_upvotes = req.body.show_upvotes;
|
||||
let domain_twitter = req.body.domain_twitter;
|
||||
let domain_youtube = req.body.domain_youtube;
|
||||
let domain_instagram = req.body.domain_instagram;
|
||||
let domain_quora = req.body.domain_quora;
|
||||
let domain_imgur = req.body.domain_imgur;
|
||||
let videos_muted = req.body.videos_muted;
|
||||
let prefer_frontpage = req.body.prefer_frontpage;
|
||||
let show_large_gallery_images = req.body.show_large_gallery_images;
|
||||
let default_comment_sort = req.body.default_comment_sort;
|
||||
|
||||
res.cookie('theme', theme, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
|
@ -136,6 +150,13 @@ preferenceRoutes.post('/saveprefs', (req, res, next) => {
|
|||
httpOnly: true,
|
||||
});
|
||||
|
||||
if (show_upvotes === 'on') show_upvotes = 'true';
|
||||
else show_upvotes = 'false';
|
||||
res.cookie('show_upvotes', show_upvotes, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
if (videos_muted === 'on') videos_muted = 'true';
|
||||
else videos_muted = 'false';
|
||||
res.cookie('videos_muted', videos_muted, {
|
||||
|
@ -155,6 +176,33 @@ preferenceRoutes.post('/saveprefs', (req, res, next) => {
|
|||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
res.cookie('domain_quora', domain_quora, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
res.cookie('domain_imgur', domain_imgur, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
if (prefer_frontpage === 'on') prefer_frontpage = 'true';
|
||||
else prefer_frontpage = 'false';
|
||||
res.cookie('prefer_frontpage', prefer_frontpage, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
if (show_large_gallery_images === 'on') show_large_gallery_images = 'true';
|
||||
else show_large_gallery_images = 'false';
|
||||
res.cookie('show_large_gallery_images', show_large_gallery_images, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
res.cookie('default_comment_sort', default_comment_sort, {
|
||||
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
});
|
||||
|
||||
return res.redirect('/preferences');
|
||||
});
|
||||
|
@ -173,7 +221,7 @@ preferenceRoutes.post('/export_prefs', (req, res, next) => {
|
|||
'Content-disposition',
|
||||
'attachment; filename=teddit_prefs.json'
|
||||
);
|
||||
res.setHeader('Content-type', 'preferenceRouteslication/json');
|
||||
res.setHeader('Content-type', 'application/json');
|
||||
return res.send(export_data);
|
||||
}
|
||||
|
||||
|
@ -204,7 +252,7 @@ preferenceRoutes.post('/import_prefs', (req, res, next) => {
|
|||
body = body.toString();
|
||||
try {
|
||||
let json = body
|
||||
.split('Content-Type: preferenceRouteslication/json')[1]
|
||||
.split('Content-Type: application/json')[1]
|
||||
.trim()
|
||||
.split('--')[0];
|
||||
let prefs = JSON.parse(json);
|
||||
|
|
|
@ -2,16 +2,9 @@ const config = require('../config');
|
|||
const { redis, fetch } = require('../app');
|
||||
const saveRoutes = require('express').Router();
|
||||
|
||||
const processUser = require('../inc/processJsonUser.js')();
|
||||
const processPost = require('../inc/processJsonPost.js')();
|
||||
const processAbout = require('../inc/processSubredditAbout.js')();
|
||||
const tedditApiUser = require('../inc/teddit_api/handleUser.js')();
|
||||
const processSearches = require('../inc/processSearchResults.js')();
|
||||
const processSubreddit = require('../inc/processJsonSubreddit.js')();
|
||||
const processJsonSubreddit = require('../inc/processJsonSubreddit.js');
|
||||
const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')();
|
||||
const processMoreComments = require('../inc/processMoreComments.js')();
|
||||
const processSubredditsExplore =
|
||||
require('../inc/processSubredditsExplore.js')();
|
||||
|
||||
saveRoutes.get('/saved', (req, res, next) => {
|
||||
let saved = req.cookies.saved;
|
||||
|
@ -20,6 +13,7 @@ saveRoutes.get('/saved', (req, res, next) => {
|
|||
return res.render('saved', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -45,6 +39,7 @@ saveRoutes.get('/saved', (req, res, next) => {
|
|||
return res.render('saved', {
|
||||
json: processed_json,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
return res.render('subreddit', {
|
||||
|
@ -52,6 +47,7 @@ saveRoutes.get('/saved', (req, res, next) => {
|
|||
error: true,
|
||||
data: processed_json,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -221,9 +217,10 @@ saveRoutes.get(
|
|||
'Error getting the short URL for post key from redis.',
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -264,9 +261,10 @@ saveRoutes.get(
|
|||
'Error setting the short URL for post key to redis.',
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -294,10 +292,11 @@ saveRoutes.get(
|
|||
`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const config = require('../config');
|
||||
const searchRoute = require('express').Router();
|
||||
|
||||
searchRoute.get('/search', (req, res, next) => {
|
||||
|
@ -14,6 +15,7 @@ searchRoute.get('/search', (req, res, next) => {
|
|||
sortby: undefined,
|
||||
past: undefined,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
const config = require('../config');
|
||||
|
||||
const staticRoutes = require('express').Router();
|
||||
|
||||
staticRoutes.get('/privacy', (req, res, next) => {
|
||||
return res.render('privacypolicy', { user_preferences: req.cookies });
|
||||
return res.render('privacypolicy', { user_preferences: req.cookies, instance_config: config });
|
||||
});
|
||||
|
||||
staticRoutes.get('/about', (req, res, next) => {
|
||||
return res.render('about', { user_preferences: req.cookies });
|
||||
return res.render('about', { user_preferences: req.cookies, instance_config: config });
|
||||
});
|
||||
|
||||
module.exports = staticRoutes;
|
||||
|
|
|
@ -2,20 +2,32 @@ const config = require('../config');
|
|||
const { redis, fetch, RedditAPI } = require('../app');
|
||||
const subredditRoutes = require('express').Router();
|
||||
|
||||
const processUser = require('../inc/processJsonUser.js')();
|
||||
const processPost = require('../inc/processJsonPost.js')();
|
||||
const processAbout = require('../inc/processSubredditAbout.js')();
|
||||
const tedditApiUser = require('../inc/teddit_api/handleUser.js')();
|
||||
const processSearches = require('../inc/processSearchResults.js')();
|
||||
const processSubreddit = require('../inc/processJsonSubreddit.js')();
|
||||
const {
|
||||
processJsonPost,
|
||||
finalizeJsonPost,
|
||||
} = require('../inc/processJsonPost.js');
|
||||
const {
|
||||
processSubredditAbout
|
||||
} = require('../inc/processSubredditAbout.js');
|
||||
const processSearchResults = require('../inc/processSearchResults.js');
|
||||
const processJsonSubreddit = require('../inc/processJsonSubreddit.js');
|
||||
const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')();
|
||||
const processMoreComments = require('../inc/processMoreComments.js')();
|
||||
const processSubredditsExplore =
|
||||
require('../inc/processSubredditsExplore.js')();
|
||||
const tedditApiPost = require('../inc/teddit_api/handlePost.js')();
|
||||
const processMoreComments = require('../inc/processMoreComments.js');
|
||||
const processJsonSubredditsExplore = require('../inc/processSubredditsExplore.js');
|
||||
|
||||
subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
||||
let subreddit = req.params.subreddit;
|
||||
let q = req.query.q;
|
||||
let api_req = req.query.api;
|
||||
let api_type = req.query.type;
|
||||
let api_target = req.query.target;
|
||||
let api_mode = req.query.mode;
|
||||
|
||||
if (req.query.hasOwnProperty('api')) api_req = true;
|
||||
else api_req = false;
|
||||
|
||||
let raw_json = api_req && req.query.raw_json == '1' ? 1 : 0;
|
||||
|
||||
if (typeof q === 'undefined') {
|
||||
return res.render('search', {
|
||||
|
@ -28,6 +40,7 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
sortby: undefined,
|
||||
past: undefined,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -56,18 +69,37 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
nsfw = 'off';
|
||||
}
|
||||
|
||||
let key = `search:${subreddit}:${q}:${restrict_sr}:${sortby}:${past}:${after}:${before}:${nsfw}`;
|
||||
let count = '&count=25';
|
||||
if (after == '') {
|
||||
count = '';
|
||||
}
|
||||
|
||||
let key = `search:${subreddit}:${q}:${restrict_sr}:${sortby}:${past}:${after}:${before}:${nsfw}:raw_json:${raw_json}`;
|
||||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error('Error getting the search key from redis.', error);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
console.log('Got search key from redis.');
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiSubredditSearch(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'redis',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit,
|
||||
q,
|
||||
api_mode
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processSearchResults(
|
||||
json,
|
||||
false,
|
||||
|
@ -85,14 +117,16 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
let url = '';
|
||||
if (config.use_reddit_oauth)
|
||||
url = `https://oauth.reddit.com/r/${subreddit}/search?api_type=json&q=${q}&restrict_sr=${restrict_sr}&include_over_18=${nsfw}&sort=${sortby}&t=${past}${d}`;
|
||||
url = `https://oauth.reddit.com/r/${subreddit}/search?api_type=json&q=${q}&restrict_sr=${restrict_sr}&include_over_18=${nsfw}&sort=${sortby}&t=${past}${count}${d}&raw_json=${raw_json}`;
|
||||
else
|
||||
url = `https://reddit.com/r/${subreddit}/search.json?api_type=json&q=${q}&restrict_sr=${restrict_sr}&include_over_18=${nsfw}&sort=${sortby}&t=${past}${d}`;
|
||||
url = `https://reddit.com/r/${subreddit}/search.json?api_type=json&q=${q}&restrict_sr=${restrict_sr}&include_over_18=${nsfw}&sort=${sortby}&t=${past}${count}${d}&raw_json=${raw_json}`;
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
.then((result) => {
|
||||
if (result.status === 200) {
|
||||
|
@ -121,13 +155,27 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
'Error setting the searches key to redis.',
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log('Fetched search results from Reddit.');
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiSubredditSearch(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'from_online',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit,
|
||||
q,
|
||||
api_mode
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processSearchResults(
|
||||
json,
|
||||
true,
|
||||
|
@ -145,7 +193,9 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
@ -157,10 +207,11 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -171,6 +222,107 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
|
|||
});
|
||||
});
|
||||
|
||||
subredditRoutes.get('/r/:subreddit/about', (req, res, next) => {
|
||||
let subreddit = req.params.subreddit;
|
||||
let api_type = req.query.type;
|
||||
let api_target = req.query.target;
|
||||
let api_mode = req.query.mode;
|
||||
|
||||
if (!req.query.hasOwnProperty('api')) {
|
||||
console.log(`This route is only available via the API.`, req.originalUrl);
|
||||
return res.redirect(`/r/${subreddit}`);
|
||||
}
|
||||
|
||||
let raw_json = req.query.raw_json == '1' ? 1 : 0;
|
||||
|
||||
let key = `about:${subreddit.toLowerCase()}:raw_json:${raw_json}`;
|
||||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error(`Error getting the about key from redis.`, error);
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
console.log(`Got about key from redis.`);
|
||||
(async () => {
|
||||
return handleTedditApiSubredditAbout(
|
||||
json,
|
||||
res,
|
||||
'redis',
|
||||
api_target
|
||||
);
|
||||
})();
|
||||
} else {
|
||||
let url = '';
|
||||
if (config.use_reddit_oauth)
|
||||
url = `https://oauth.reddit.com/r/${subreddit}/about.json?api_type=json&raw_json=${raw_json}`;
|
||||
else
|
||||
url = `https://reddit.com/r/${subreddit}/about.json?api_type=json&raw_json=${raw_json}`;
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
.then((result) => {
|
||||
if (result.status === 200) {
|
||||
result.json().then((json) => {
|
||||
redis.setex(
|
||||
key,
|
||||
config.setexs.subreddit,
|
||||
JSON.stringify(json),
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.error(
|
||||
`Error setting the about key to redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('subreddit', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
`Fetched the JSON from reddit.com/r/${subreddit}/about.`
|
||||
);
|
||||
(async () => {
|
||||
return handleTedditApiSubredditAbout(
|
||||
json,
|
||||
res,
|
||||
'from_online',
|
||||
api_target
|
||||
);
|
||||
})();
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
if (result.status === 404) {
|
||||
console.log('404 – Subreddit not found');
|
||||
} else {
|
||||
console.error(
|
||||
`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
`Error fetching the JSON file from reddit.com/r/${subreddit}/about.`,
|
||||
error
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
subredditRoutes.get(
|
||||
'/r/:subreddit/wiki/:page?/:sub_page?',
|
||||
(req, res, next) => {
|
||||
|
@ -201,9 +353,10 @@ subredditRoutes.get(
|
|||
`Error getting the ${subreddit} wiki key from redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -216,6 +369,7 @@ subredditRoutes.get(
|
|||
: formatWikipagelisting(json, subreddit),
|
||||
subreddit: subreddit,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
let url = '';
|
||||
|
@ -240,6 +394,7 @@ subredditRoutes.get(
|
|||
return res.render('subreddit', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -252,6 +407,7 @@ subredditRoutes.get(
|
|||
: formatWikipagelisting(json, subreddit),
|
||||
subreddit: subreddit,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -266,10 +422,11 @@ subredditRoutes.get(
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -323,6 +480,7 @@ subredditRoutes.get('/r/random', (req, res, next) => {
|
|||
return res.render('subreddit', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -334,9 +492,10 @@ subredditRoutes.get('/r/random', (req, res, next) => {
|
|||
);
|
||||
} else {
|
||||
console.error(`Fetching random subreddit failed.`, json);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -349,10 +508,11 @@ subredditRoutes.get('/r/random', (req, res, next) => {
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -373,6 +533,7 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
let api_req = req.query.api;
|
||||
let api_type = req.query.type;
|
||||
let api_target = req.query.target;
|
||||
let api_mode = req.query.mode;
|
||||
|
||||
if (req.query.hasOwnProperty('api')) api_req = true;
|
||||
else api_req = false;
|
||||
|
@ -414,9 +575,10 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error(`Error getting the ${subreddit} key from redis.`, error);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -430,7 +592,8 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
'redis',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit
|
||||
subreddit,
|
||||
api_mode
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -458,6 +621,7 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
redis_key: key,
|
||||
after: req.query.after,
|
||||
before: req.query.before,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
return res.render('subreddit', {
|
||||
|
@ -465,6 +629,7 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
error: true,
|
||||
data: processed_json,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -492,6 +657,7 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
return res.render('subreddit', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -506,7 +672,8 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
'from_online',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit
|
||||
subreddit,
|
||||
api_mode
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -533,6 +700,7 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
redis_key: key,
|
||||
after: req.query.after,
|
||||
before: req.query.before,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -549,10 +717,11 @@ subredditRoutes.get('/r/:subreddit/:sort?', (req, res, next) => {
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -572,17 +741,30 @@ subredditRoutes.get(
|
|||
let subreddit = req.params.subreddit;
|
||||
let id = req.params.id;
|
||||
let snippet = encodeURIComponent(req.params.snippet);
|
||||
let sortby = req.query.sort;
|
||||
let sortby = req.query.sort || req.cookies.default_comment_sort;
|
||||
let comment_id = '';
|
||||
let viewing_comment = false;
|
||||
let comment_ids = req.query.comment_ids;
|
||||
let context = parseInt(req.query.context);
|
||||
let api_req = req.query.api;
|
||||
let api_type = req.query.type;
|
||||
let api_target = req.query.target;
|
||||
|
||||
if (req.query.hasOwnProperty('api')) api_req = true;
|
||||
else api_req = false;
|
||||
|
||||
let raw_json = api_req && req.query.raw_json == '1' ? 1 : 0;
|
||||
|
||||
if (req.params.comment_id) {
|
||||
comment_id = `${req.params.comment_id}/`;
|
||||
viewing_comment = true;
|
||||
}
|
||||
|
||||
if (sortby === 'best') {
|
||||
// in Reddit the sorting "best" is the label, but the actual key "confidence"
|
||||
sortby = 'confidence';
|
||||
}
|
||||
|
||||
if (!sortby) {
|
||||
sortby = config.post_comments_sort;
|
||||
}
|
||||
|
@ -604,7 +786,7 @@ subredditRoutes.get(
|
|||
|
||||
let comments_url = `/r/${subreddit}/comments/${id}/${snippet}/${comment_id}`;
|
||||
let post_url = `/r/${subreddit}/comments/${id}/${snippet}/`;
|
||||
let comments_key = `${comments_url}:sort:${sortby}`;
|
||||
let comments_key = `${comments_url}:sort:${sortby}:raw_json:${raw_json}`;
|
||||
|
||||
redis.get(comments_key, (error, json) => {
|
||||
if (error) {
|
||||
|
@ -612,19 +794,30 @@ subredditRoutes.get(
|
|||
`Error getting the ${comments_url} key from redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
post: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
console.log(`Got ${comments_url} key from redis.`);
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiPost(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'redis',
|
||||
api_type,
|
||||
api_target
|
||||
);
|
||||
} else {
|
||||
let parsed = false;
|
||||
let more_comments = null;
|
||||
if (comment_ids) {
|
||||
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`;
|
||||
more_comments = await moreComments(
|
||||
more_comments = await processMoreComments(
|
||||
fetch,
|
||||
redis,
|
||||
post_url,
|
||||
|
@ -662,14 +855,16 @@ subredditRoutes.get(
|
|||
instance_videos_muted: config.videos_muted,
|
||||
post_media_max_heights: config.post_media_max_heights,
|
||||
redis_key: comments_key,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
let url = '';
|
||||
if (config.use_reddit_oauth)
|
||||
url = `https://oauth.reddit.com${comments_url}?api_type=json&sort=${sortby}&context=${context}`;
|
||||
url = `https://oauth.reddit.com${comments_url}?api_type=json&sort=${sortby}&context=${context}&raw_json=${raw_json}`;
|
||||
else
|
||||
url = `https://reddit.com${comments_url}.json?api_type=json&sort=${sortby}&context=${context}`;
|
||||
url = `https://reddit.com${comments_url}.json?api_type=json&sort=${sortby}&context=${context}&raw_json=${raw_json}`;
|
||||
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
.then((result) => {
|
||||
|
@ -688,16 +883,27 @@ subredditRoutes.get(
|
|||
return res.render('post', {
|
||||
post: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
`Fetched the JSON from reddit.com${comments_url}.`
|
||||
);
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiPost(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'from_online',
|
||||
api_type,
|
||||
api_target
|
||||
);
|
||||
} else {
|
||||
let more_comments = null;
|
||||
if (comment_ids) {
|
||||
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`;
|
||||
more_comments = await moreComments(
|
||||
more_comments = await processMoreComments(
|
||||
fetch,
|
||||
redis,
|
||||
post_url,
|
||||
|
@ -722,7 +928,8 @@ subredditRoutes.get(
|
|||
id,
|
||||
post_url,
|
||||
more_comments,
|
||||
viewing_comment
|
||||
viewing_comment,
|
||||
req.cookies
|
||||
);
|
||||
return res.render('post', {
|
||||
post: finalized_json.post_data,
|
||||
|
@ -736,7 +943,9 @@ subredditRoutes.get(
|
|||
instance_videos_muted: config.videos_muted,
|
||||
post_media_max_heights: config.post_media_max_heights,
|
||||
redis_key: comments_key,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
@ -751,11 +960,12 @@ subredditRoutes.get(
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
http_statustext: result.statusText,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -800,6 +1010,14 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
let before = req.query.before;
|
||||
let sortby = req.params.sort;
|
||||
let searching = false;
|
||||
let api_req = req.query.api;
|
||||
let api_type = req.query.type;
|
||||
let api_target = req.query.target;
|
||||
|
||||
if (req.query.hasOwnProperty('api')) api_req = true;
|
||||
else api_req = false;
|
||||
|
||||
let raw_json = api_req && req.query.raw_json == '1' ? 1 : 0;
|
||||
|
||||
if (!after) {
|
||||
after = '';
|
||||
|
@ -821,26 +1039,38 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
sortby = '';
|
||||
}
|
||||
|
||||
let key = `subreddits:sort:${sortby}${d}`;
|
||||
let key = `subreddits:sort:${sortby}${d}:raw_json:${raw_json}`;
|
||||
|
||||
if (sortby === 'search') {
|
||||
if (typeof q == 'undefined' || q == '') return res.redirect('/subreddits');
|
||||
|
||||
key = `subreddits:search:q:${q}:nsfw:${nsfw}${d}`;
|
||||
key = `subreddits:search:q:${q}:nsfw:${nsfw}${d}:raw_json:${raw_json}`;
|
||||
searching = true;
|
||||
}
|
||||
|
||||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error(`Error getting the subreddits key from redis.`, error);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
console.log(`Got subreddits key from redis.`);
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiSubredditsExplore(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'redis',
|
||||
api_type,
|
||||
api_target,
|
||||
q
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubredditsExplore(
|
||||
json,
|
||||
'redis',
|
||||
|
@ -859,6 +1089,7 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
subreddits_front: !before && !after ? true : false,
|
||||
user_preferences: req.cookies,
|
||||
instance_nsfw_enabled: config.nsfw_enabled,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
return res.render('subreddits_explore', {
|
||||
|
@ -866,21 +1097,23 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
error: true,
|
||||
data: processed_json,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
let url = '';
|
||||
if (config.use_reddit_oauth) {
|
||||
if (!searching)
|
||||
url = `https://oauth.reddit.com/subreddits/${sortby}?api_type=json&count=25&g=GLOBAL&t=${d}`;
|
||||
url = `https://oauth.reddit.com/subreddits/${sortby}?api_type=json&count=25&g=GLOBAL&t=${d}&raw_json=${raw_json}`;
|
||||
else
|
||||
url = `https://oauth.reddit.com/subreddits/search?api_type=json&q=${q}&include_over_18=${nsfw}${d}`;
|
||||
url = `https://oauth.reddit.com/subreddits/search?api_type=json&q=${q}&include_over_18=${nsfw}${d}&raw_json=${raw_json}`;
|
||||
} else {
|
||||
if (!searching)
|
||||
url = `https://reddit.com/subreddits/${sortby}.json?api_type=json&count=25&g=GLOBAL&t=${d}`;
|
||||
url = `https://reddit.com/subreddits/${sortby}.json?api_type=json&count=25&g=GLOBAL&t=${d}&raw_json=${raw_json}`;
|
||||
else
|
||||
url = `https://reddit.com/subreddits/search.json?api_type=json&q=${q}&include_over_18=${nsfw}${d}`;
|
||||
url = `https://reddit.com/subreddits/search.json?api_type=json&q=${q}&include_over_18=${nsfw}${d}&raw_json=${raw_json}`;
|
||||
}
|
||||
|
||||
fetch(encodeURI(url), redditApiGETHeaders())
|
||||
|
@ -899,10 +1132,22 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
return res.render('subreddits_explore', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(`Fetched the JSON from reddit.com/subreddits.`);
|
||||
(async () => {
|
||||
if (api_req) {
|
||||
return handleTedditApiSubredditsExplore(
|
||||
json,
|
||||
req,
|
||||
res,
|
||||
'from_online',
|
||||
api_type,
|
||||
api_target,
|
||||
q
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubredditsExplore(
|
||||
json,
|
||||
'from_online',
|
||||
|
@ -920,7 +1165,9 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
subreddits_front: !before && !after ? true : false,
|
||||
user_preferences: req.cookies,
|
||||
instance_nsfw_enabled: config.nsfw_enabled,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
});
|
||||
|
@ -934,10 +1181,11 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,16 +2,11 @@ const config = require('../config');
|
|||
const { redis, fetch } = require('../app');
|
||||
const userRoutes = require('express').Router();
|
||||
|
||||
const processUser = require('../inc/processJsonUser.js')();
|
||||
const processPost = require('../inc/processJsonPost.js')();
|
||||
const processAbout = require('../inc/processSubredditAbout.js')();
|
||||
const processJsonUser = require('../inc/processJsonUser.js');
|
||||
const tedditApiUser = require('../inc/teddit_api/handleUser.js')();
|
||||
const processSearches = require('../inc/processSearchResults.js')();
|
||||
const processSubreddit = require('../inc/processJsonSubreddit.js')();
|
||||
const processJsonSubreddit = require('../inc/processJsonSubreddit.js');
|
||||
const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')();
|
||||
const processMoreComments = require('../inc/processMoreComments.js')();
|
||||
const processSubredditsExplore =
|
||||
require('../inc/processSubredditsExplore.js')();
|
||||
|
||||
userRoutes.get('/user/:user/:kind?', (req, res, next) => {
|
||||
let kind = '';
|
||||
|
@ -96,9 +91,10 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
redis.get(key, (error, json) => {
|
||||
if (error) {
|
||||
console.error(`Error getting the user ${key} key from redis.`, error);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -131,6 +127,7 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -168,9 +165,10 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
`Error setting the user ${key} key to redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
post: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
(async () => {
|
||||
|
@ -201,22 +199,33 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
sortby: sortby,
|
||||
past: past,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
);
|
||||
}).catch(error => {
|
||||
console.error(`Something went wrong while fetching data from Reddit API: invalid or non-JSON data was returned.`);
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: 500,
|
||||
http_statustext: "Invalid response from Reddit",
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.error(
|
||||
`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText}`
|
||||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -225,10 +234,11 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
`Error fetching the overview JSON file from reddit.com/u/${user}`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -241,11 +251,12 @@ userRoutes.get('/u/:user/:kind?', (req, res, next) => {
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
http_statustext: result.statusText,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
@ -316,9 +327,10 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
`Error getting the ${user} custom_feed key from redis.`,
|
||||
error
|
||||
);
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
if (json) {
|
||||
|
@ -332,7 +344,8 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
'redis',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit
|
||||
subreddit,
|
||||
'full'
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -354,6 +367,7 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
redis_key: key,
|
||||
after: req.query.after,
|
||||
before: req.query.before,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
return res.render('subreddit', {
|
||||
|
@ -361,6 +375,7 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
error: true,
|
||||
data: processed_json,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -388,6 +403,7 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
return res.render('subreddit', {
|
||||
json: null,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -402,7 +418,8 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
'from_online',
|
||||
api_type,
|
||||
api_target,
|
||||
subreddit
|
||||
subreddit,
|
||||
'full'
|
||||
);
|
||||
} else {
|
||||
let processed_json = await processJsonSubreddit(
|
||||
|
@ -423,6 +440,7 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
redis_key: key,
|
||||
after: req.query.after,
|
||||
before: req.query.before,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -439,10 +457,11 @@ userRoutes.get('/u/:user/m/:custom_feed/:sort?', (req, res, next) => {
|
|||
);
|
||||
console.error(config.reddit_api_error_text);
|
||||
}
|
||||
return res.render('index', {
|
||||
return res.render('frontpage', {
|
||||
json: null,
|
||||
http_status_code: result.status,
|
||||
user_preferences: req.cookies,
|
||||
instance_config: config,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
:root {
|
||||
--darkbg: #2E3440;
|
||||
--darkbglight: #434C5E;
|
||||
--darklinkcolor: #599bff;
|
||||
}
|
||||
|
||||
body.nord {
|
||||
background: var(--darkbg);
|
||||
color: #ECEFF4;
|
||||
}
|
||||
body.nord nav {
|
||||
background: #3E4450;
|
||||
}
|
||||
body.nord .top-links a {
|
||||
background: var(--darkbg);
|
||||
color: #bfbfbf;
|
||||
}
|
||||
body.nord header {
|
||||
background: var(--darkbglight);
|
||||
color: #f1f1f1;
|
||||
}
|
||||
body.nord #post header div a {
|
||||
color: var(--darklinkcolor);
|
||||
text-decoration: none;
|
||||
}
|
||||
body.nord a {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
body.nord a:hover, body.nord a:focus {
|
||||
color: #88C0D0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
body.nord #post header div a:hover,
|
||||
body.nord #post header div a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
body.nord input[type="submit"]:hover,
|
||||
body.nord input[type="submit"]:focus,
|
||||
body.nord .btn:hover,
|
||||
body.nord .btn:focus {
|
||||
background: #ECEFF4;
|
||||
color: #2E3440;
|
||||
text-decoration: none;
|
||||
}
|
||||
body.nord form legend {
|
||||
border-bottom: 1px solid #353535;
|
||||
}
|
||||
body.nord #post .title a {
|
||||
color: var(--darklinkcolor);
|
||||
}
|
||||
body.nord #post .submitted {
|
||||
color: #a5a5a5;
|
||||
}
|
||||
body.nord #post .usertext-body {
|
||||
background: #2A2935;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
body.nord .infobar {
|
||||
background-color: #d2d2d2;
|
||||
color: #2f2f2f;
|
||||
}
|
||||
body.nord .infobar.blue {
|
||||
background: #c7e3f9;
|
||||
border: 1px solid #4b78a4;
|
||||
}
|
||||
body.nord .infobar a {
|
||||
color: #0356d4;
|
||||
}
|
||||
body.nord header .tabmenu li a {
|
||||
background: #3e3e3e;
|
||||
}
|
||||
body.nord header .tabmenu li a:hover, body.nord header .tabmenu li a:focus {
|
||||
text-decoration: underline;
|
||||
color: #ECEFF4;
|
||||
}
|
||||
body.nord #search {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
body.nord .md {
|
||||
color: #dadada;
|
||||
}
|
||||
body.nord .md blockquote, body.nord .md del {
|
||||
color: #777777;
|
||||
}
|
||||
body.nord .md code, body.nord .md pre {
|
||||
background: #2E3440;
|
||||
color: #cacaca;
|
||||
}
|
||||
body.nord .comment .body blockquote {
|
||||
background: #2E3440;
|
||||
color: #afafaf;
|
||||
border-color: #464646;
|
||||
}
|
||||
body.nord .even-depth {
|
||||
background: var(--darkbg);
|
||||
}
|
||||
body.nord .odd-depth {
|
||||
background: var(--darkbglight);
|
||||
}
|
||||
|
||||
body.nord .comment .comment {
|
||||
border-left: 1px solid #545454;
|
||||
}
|
||||
|
||||
body.nord .comment .meta .created a {
|
||||
color: #7b7b7b;
|
||||
}
|
||||
body.nord .comment details summary {
|
||||
color: #868686;
|
||||
}
|
||||
body.nord .comment details summary::-webkit-details-marker,
|
||||
body.nord .comment details summary::marker {
|
||||
color: #868686;
|
||||
}
|
||||
body.nord #links .link .entry .title a h2 {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
body.nord #links .link .entry .title a:visited h2 {
|
||||
color: #8FBCBB;
|
||||
}
|
||||
body.nord #links .link .image .no-image,
|
||||
body.nord #user .entry .image .no-image {
|
||||
filter: opacity(0.5);
|
||||
}
|
||||
body.nord #user .comment {
|
||||
width: 100%;
|
||||
background: var(--darkbg);
|
||||
}
|
||||
body.nord #links .link .upvotes {
|
||||
color: #D08770;
|
||||
}
|
||||
body.nord .upvotes .arrow,
|
||||
body.nord .score .arrow {
|
||||
filter: opacity(0.5);
|
||||
}
|
||||
body.nord #links .link .entry .meta a {
|
||||
color: #81A1C1;
|
||||
}
|
||||
#links .link .entry .meta {
|
||||
color: #D8DEE9 !important;
|
||||
}
|
||||
#links .link .entry .title span {
|
||||
color: #5E81AC !important;
|
||||
}
|
||||
body.nord #links .link .entry .selftext {
|
||||
background: #2A2935;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
body.nord #links .link .entry .meta .links .selftext a {
|
||||
color: var(--darklinkcolor);
|
||||
margin: 0;
|
||||
}
|
||||
body.nord #links .link .entry details .line {
|
||||
width: 16px;
|
||||
margin-top: 3px;
|
||||
background: #4C566A;
|
||||
border: 1px solid #81A1C1;
|
||||
}
|
||||
body.nord .content .bottom img {
|
||||
filter: invert(1);
|
||||
}
|
||||
body.nord .container .content {
|
||||
border: 1px solid #434C5E;
|
||||
}
|
||||
body.nord input[type="submit"],
|
||||
body.nord .btn {
|
||||
background: #2E3440;
|
||||
color: #ECEFF4;
|
||||
}
|
||||
body.nord #post .crosspost {
|
||||
background: var(--darkbg);
|
||||
}
|
||||
body.nord .view-more-links a {
|
||||
background: #2E3440;
|
||||
color: #cacaca;
|
||||
}
|
||||
body.nord .md .md-spoiler-text:not(.revealed):active,
|
||||
body.nord .md .md-spoiler-text:not(.revealed):focus,
|
||||
body.nord .md .md-spoiler-text:not(.revealed):hover {
|
||||
background: #cacaca;
|
||||
color: #2E3440;
|
||||
}
|
||||
body.nord .comment .body a,
|
||||
body.nord .usertext-body a {
|
||||
color: #3d99fb;
|
||||
}
|
||||
body.nord header .tabmenu li.active a {
|
||||
background: #acacac;
|
||||
color: #151515;
|
||||
}
|
||||
body.nord #search form input[type="text"] {
|
||||
background: #2E3440;
|
||||
color: #ECEFF4;
|
||||
}
|
||||
body.nord footer {
|
||||
background: #2f2f2f;
|
||||
}
|
||||
body.nord footer a {
|
||||
color: #999;
|
||||
}
|
||||
body.nord .flair {
|
||||
color: #eaeaea !important;
|
||||
background-color: #404040 !important;
|
||||
}
|
||||
body.nord #sr-more-link {
|
||||
color: #ECEFF4;
|
||||
background: #2E3440;
|
||||
}
|
||||
body.nord #post .usertext-body .poll {
|
||||
border: 1px solid #404040;
|
||||
}
|
|
@ -84,6 +84,7 @@ nav .nav-item.left a {
|
|||
}
|
||||
nav .nav-item.left img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: bottom;
|
||||
margin: 0 7px 0 0;
|
||||
}
|
||||
|
@ -280,9 +281,11 @@ header .tabmenu li.active a {
|
|||
color: white;
|
||||
padding: 16px;
|
||||
}
|
||||
input, select {
|
||||
padding: 2px;
|
||||
}
|
||||
input[type="submit"],
|
||||
.btn {
|
||||
padding: 3px;
|
||||
margin-top: 7px;
|
||||
margin-right: 10px;
|
||||
border-radius: 0;
|
||||
|
@ -749,6 +752,14 @@ footer a {
|
|||
#post .submitted span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
#post .source-details {
|
||||
float: left;
|
||||
margin: 10px 0 10px 30px;
|
||||
}
|
||||
#post .source-details summary:hover {
|
||||
color: var(--linkcolor);
|
||||
text-decoration: underline;
|
||||
}
|
||||
#post .comments {
|
||||
float: left;
|
||||
width: 100%;
|
||||
|
@ -1572,6 +1583,103 @@ code {
|
|||
padding:4px;
|
||||
margin:5px 0
|
||||
}
|
||||
|
||||
/* "CLEANED HOMEPAGE" SECTION */
|
||||
body.homepage.clean {
|
||||
margin: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
body.homepage.clean main {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
body.homepage.clean h1 {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 3rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.homepage.clean form {
|
||||
width: 100vw;
|
||||
max-width: 750px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body.homepage.clean input[name="q"] {
|
||||
width: 90%;
|
||||
padding: 0.4rem;
|
||||
border: none;
|
||||
color: white;
|
||||
background: #555;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
body.homepage.clean .sublinks {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
max-width: 650px;
|
||||
}
|
||||
|
||||
body.homepage.clean .sublinks a {
|
||||
color: gray;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.homepage.clean .top-links {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
body.homepage.clean form, body.homepage.clean .sublinks {
|
||||
width: 90%;
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Large gallery items */
|
||||
.gallery .item.large {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.gallery .item.large img {
|
||||
max-height: 90vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.gallery .item.large .caption {
|
||||
position: absolute;
|
||||
width: calc(100% - 0.6rem);
|
||||
color: white;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
padding: 0.3rem;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.gallery .item.large img {
|
||||
max-height: unset;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix spoiler texts not showing without JS */
|
||||
.md .md-spoiler-text:not(.revealed):active,.md .md-spoiler-text:not(.revealed):focus,.md .md-spoiler-text:not(.revealed):hover {
|
||||
color: black;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../instances.json
|
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
|
@ -1,2 +1,3 @@
|
|||
User-agent: MJ12bot
|
||||
User-agent: Applebot
|
||||
Disallow: /
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title about - teddit
|
||||
meta(property='og:title', content='about - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
@ -18,8 +21,10 @@ html
|
|||
a(href="/privacy") Privacy policy
|
||||
h2 Donating
|
||||
p(class="word-break") XMR: 832ogRwuoSs2JGYg7wJTqshidK7dErgNdfpenQ9dzMghNXQTJRby1xGbqC3gW3GAifRM9E84J91VdMZRjoSJ32nkAZnaCEj
|
||||
h2 Legal
|
||||
p Teddit does not host any content. All content shown on any Teddit instances is from Reddit™. Reddit is a trademark of Reddit Inc. Teddit is not affiliated with Reddit Inc. Any issues with content shown on any Teddit instances need to be reported to Reddit, not the instance host's internet provider or domain provider.
|
||||
.bottom
|
||||
a(href="https://en.wikipedia.org/wiki/Piratbyr%C3%A5n#Kopimi", target="_blank")
|
||||
img(src="kopimi.gif")
|
||||
p.version v.0.4.0
|
||||
p.version v.0.4.9
|
||||
include includes/footer.pug
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
.link
|
||||
if user_preferences.show_upvotes === 'false'
|
||||
style.
|
||||
.upvotes {
|
||||
display: none;
|
||||
}
|
||||
.upvotes
|
||||
.arrow
|
||||
span #{kFormatter(link.ups)}
|
||||
|
@ -92,3 +97,4 @@
|
|||
a(href="/unsave/" + link.id + "/?rk=" + redis_key + "&b=" + back_url + "") unsave
|
||||
else
|
||||
a(href="/save/" + link.id + "/?rk=" + redis_key + "&b=" + back_url + "") save
|
||||
a(href=("https://www.reddit.com" + link.permalink) target="_blank" title="Open in Reddit (new tab)") [R↗]
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title teddit
|
||||
meta(property='og:title', content='frontpage : teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
@ -38,6 +41,7 @@ html
|
|||
#intro
|
||||
h1 Welcome to teddit
|
||||
h2 the alternative, privacy respecting, front page of internet.
|
||||
|
||||
#links.sr
|
||||
if sortby === 'top' || sortby === 'controversial'
|
||||
details
|
|
@ -0,0 +1,33 @@
|
|||
doctype html
|
||||
html
|
||||
head
|
||||
title teddit
|
||||
meta(property='og:title', content='home : teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class="" + (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + " homepage clean")
|
||||
include includes/topbar.pug
|
||||
main
|
||||
h1 teddit
|
||||
form(action="/search", method="GET")
|
||||
input(type="text", name="q")
|
||||
input(type="hidden", name="restrict_sr", value="on")
|
||||
input(type="hidden", name="nsfw", value="on")
|
||||
input(type="hidden", name="sort", value="relevance")
|
||||
input(type="hidden", name="t", value="all")
|
||||
.sublinks
|
||||
if user_preferences.subbed_subreddits && Array.isArray(user_preferences.subbed_subreddits)
|
||||
a(href="/r/popular") Popular
|
||||
a(href="/r/all") All
|
||||
a(href="/saved") Saved
|
||||
each subreddit in user_preferences.subbed_subreddits
|
||||
a(href="/r/" + subreddit) #{subreddit}
|
||||
else if instance_config.suggested_subreddits && Array.isArray(instance_config.suggested_subreddits)
|
||||
each subreddit in instance_config.suggested_subreddits
|
||||
if subreddit.toLowerCase() === 'saved'
|
||||
a(href="/saved") Saved
|
||||
else
|
||||
a(href="/r/" + subreddit) #{subreddit}
|
||||
include includes/footer.pug
|
||||
|
|
@ -4,8 +4,11 @@ if(user_preferences.theme === 'dark')
|
|||
link(rel="stylesheet", type="text/css", href="/css/dark.css")
|
||||
if(user_preferences.theme === 'sepia')
|
||||
link(rel="stylesheet", type="text/css", href="/css/sepia.css")
|
||||
if(user_preferences.theme === 'nord')
|
||||
link(rel="stylesheet", type="text/css", href="/css/nord.css")
|
||||
link(rel="stylesheet", type="text/css", href="/css/styles.css")
|
||||
link(rel="icon", type="image/png", sizes="32x32", href="/favicon.png")
|
||||
meta(property='og:site_name', content='teddit')
|
||||
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
||||
-
|
||||
if(!user_preferences)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
meta(property='og:type', content='website')
|
||||
meta(name='twitter:card', content='summary')
|
||||
include meta_logo.pug
|
|
@ -0,0 +1 @@
|
|||
meta(property='og:description', content='Teddit is a free and open source alternative Reddit front-end focused on privacy. Teddit doesn\'t require you to have JavaScript enabled in your browser.')
|
|
@ -0,0 +1,4 @@
|
|||
meta(property='og:image', content='/logo512.png')
|
||||
meta(property='og:image:width', content='128')
|
||||
meta(property='og:image:height', content='128')
|
||||
meta(property='og:author_name', content='')
|
|
@ -0,0 +1,43 @@
|
|||
meta(property='og:title', content=cleanTitle(post.title) + ' : r/' + subreddit)
|
||||
meta(property='og:description', content='' + post.selftext_preview)
|
||||
meta(property='og:author_name', content='u/' + post.author)
|
||||
if !post.has_media
|
||||
if post.gallery
|
||||
meta(property='twitter:card', content='summary_large_image')
|
||||
meta(property='og:type', content='image')
|
||||
each item in post.gallery_items
|
||||
meta(property='og:image', content='' + item.large)
|
||||
else
|
||||
if post.images
|
||||
meta(property='twitter:card', content='summary_large_image')
|
||||
meta(property='og:type', content='image')
|
||||
meta(property='og:image', content='' + post.images.source)
|
||||
meta(property='og:image:url', content='' + post.images.source)
|
||||
else
|
||||
include meta_logo.pug
|
||||
else
|
||||
if post.media
|
||||
if post.media.not_hosted_in_reddit
|
||||
if post.media.source === 'YouTube'
|
||||
meta(property='twitter:card', content='player')
|
||||
meta(property='og:type', content='video')
|
||||
meta(property='og:video', content='' + post.media.embed_src)
|
||||
else
|
||||
if post.media.source === 'external'
|
||||
if post.images
|
||||
meta(name='twitter:card', content='summary_large_image')
|
||||
meta(property='og:type', content='image')
|
||||
meta(property='og:image', content='' + post.images.source)
|
||||
meta(property='og:image:src', content='' + post.images.source)
|
||||
else
|
||||
meta(name='twitter:card', content='summary_large_image')
|
||||
meta(property='og:type', content='image')
|
||||
meta(property='og:image', content='' + post.media.source)
|
||||
meta(property='og:image:url', content='' + post.media.source)
|
||||
else
|
||||
meta(property='twitter:card', content='player')
|
||||
meta(property='og:type', content='video')
|
||||
meta(property='og:video', content='' + post.media.source)
|
||||
meta(property='og:video:type', content='video/mp4')
|
||||
else
|
||||
include meta_logo.pug
|
|
@ -16,55 +16,10 @@ div#topbar
|
|||
a(href="/saved") Saved
|
||||
each subreddit in user_preferences.subbed_subreddits
|
||||
a(href="/r/" + subreddit) #{subreddit}
|
||||
else
|
||||
a(href="/r/popular") Popular
|
||||
a(href="/r/all") All
|
||||
else if instance_config.suggested_subreddits && Array.isArray(instance_config.suggested_subreddits)
|
||||
each subreddit in instance_config.suggested_subreddits
|
||||
if subreddit.toLowerCase() === 'saved'
|
||||
a(href="/saved") Saved
|
||||
a(href="/r/AskReddit") AskReddit
|
||||
a(href="/r/pics") pics
|
||||
a(href="/r/news") news
|
||||
a(href="/r/worldnews") worldnews
|
||||
a(href="/r/funny") funny
|
||||
a(href="/r/tifu") tifu
|
||||
a(href="/r/videos") videos
|
||||
a(href="/r/gaming") gaming
|
||||
a(href="/r/aww") aww
|
||||
a(href="/r/todayilearned") todayilearned
|
||||
a(href="/r/gifs") gifs
|
||||
a(href="/r/Art") Art
|
||||
a(href="/r/explainlikeimfive") explainlikeimfive
|
||||
a(href="/r/movies") movies
|
||||
a(href="/r/Jokes") Jokes
|
||||
a(href="/r/TwoXChromosomes") TwoXChromosomes
|
||||
a(href="/r/mildlyinteresting") mildlyinteresting
|
||||
a(href="/r/LifeProTips") LifeProTips
|
||||
a(href="/r/askscience") askscience
|
||||
a(href="/r/IAmA") IAmA
|
||||
a(href="/r/dataisbeautiful") dataisbeautiful
|
||||
a(href="/r/books") books
|
||||
a(href="/r/science") science
|
||||
a(href="/r/Showerthoughts") Showerthoughts
|
||||
a(href="/r/gadgets") gadgets
|
||||
a(href="/r/Futurology") Futurology
|
||||
a(href="/r/nottheonion") nottheonion
|
||||
a(href="/r/history") history
|
||||
a(href="/r/sports") sports
|
||||
a(href="/r/OldSchoolCool") OldSchoolCool
|
||||
a(href="/r/GetMotivated") GetMotivated
|
||||
a(href="/r/DIY") DIY
|
||||
a(href="/r/photoshopbattles") photoshopbattles
|
||||
a(href="/r/nosleep") nosleep
|
||||
a(href="/r/Music") Music
|
||||
a(href="/r/space") space
|
||||
a(href="/r/food") food
|
||||
a(href="/r/UpliftingNews") UpliftingNews
|
||||
a(href="/r/EarthPorn") EarthPorn
|
||||
a(href="/r/Documentaries") Documentaries
|
||||
a(href="/r/InternetIsBeautiful") InternetIsBeautiful
|
||||
a(href="/r/WritingPrompts") WritingPrompts
|
||||
a(href="/r/creepy") creepy
|
||||
a(href="/r/philosophy") philosophy
|
||||
a(href="/r/announcements") announcements
|
||||
a(href="/r/listentothis") listentothis
|
||||
a(href="/r/blog") blog
|
||||
else
|
||||
a(href="/r/" + subreddit) #{subreddit}
|
||||
a(href="/subreddits", id="sr-more-link") more »
|
||||
|
|
|
@ -2,6 +2,7 @@ doctype html
|
|||
html
|
||||
head
|
||||
title #{cleanTitle(post.title)} : #{subreddit}
|
||||
include includes/meta_post.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
@ -46,6 +47,12 @@ html
|
|||
video_muted = false
|
||||
}
|
||||
.info
|
||||
if user_preferences.show_upvotes === 'false'
|
||||
style.
|
||||
.comment .meta .ups, #post .score, #user .upvotes {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.score
|
||||
div.arrow
|
||||
span #{kFormatter(post.ups)}
|
||||
|
@ -80,6 +87,7 @@ html
|
|||
a(href="/unsave/" + post.id + "/?rk=" + redis_key + "&b=" + back_url + "") unsave
|
||||
else
|
||||
a(href="/save/" + post.id + "/?rk=" + redis_key + "&b=" + back_url + "") save
|
||||
a(href=("https://www.reddit.com" + back_url) target="_blank" title="Open in Reddit (new tab)" style="margin-left: 10px") [R↗]
|
||||
if post.crosspost.is_crosspost === true
|
||||
.crosspost
|
||||
.title
|
||||
|
@ -130,6 +138,13 @@ html
|
|||
if post.gallery
|
||||
.gallery
|
||||
each item in post.gallery_items
|
||||
if user_preferences.show_large_gallery_images == 'true'
|
||||
.item.large
|
||||
a(href="" + item.large + "", target="_blank")
|
||||
img(src="" + item.large + "", title="" + item.caption + "")
|
||||
if item.caption
|
||||
span.caption !{item.caption}
|
||||
else
|
||||
.item
|
||||
div
|
||||
a(href="" + item.large + "", target="_blank")
|
||||
|
@ -163,8 +178,9 @@ html
|
|||
a(href="" + post.media.embed_src + "", target="_blank", rel="noopener noreferrer")
|
||||
img(src="" + post.images.source + "", alt="")
|
||||
if !post.media.embed_src.startsWith("https://twitter.com")
|
||||
details(class="source-details")
|
||||
summary Source
|
||||
p
|
||||
| source:
|
||||
a(href="" + post.media.embed_src + "", target="_blank", rel="noopener noreferrer")
|
||||
p(class="source-url") #{post.media.embed_src}
|
||||
else
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title preferences - teddit
|
||||
meta(property='og:title', content='preferences - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
@ -11,23 +14,29 @@ html
|
|||
form(action="/saveprefs", method="POST")
|
||||
legend Privacy
|
||||
.setting
|
||||
label(for="domain_twitter") Replace Twitter links with Nitter (blank to disable):
|
||||
label(for="domain_twitter") Replace Twitter links with <a href="https://github.com/zedeus/nitter">Nitter</a> (blank to disable):
|
||||
if(user_preferences.domain_twitter != '' && typeof(user_preferences.domain_twitter) != 'undefined')
|
||||
input(type="text", name="domain_twitter", id="domain_twitter", value="" + user_preferences.domain_twitter + "", placeholder="e.g. nitter.net")
|
||||
else
|
||||
input(type="text", name="domain_twitter", id="domain_twitter", placeholder="e.g. nitter.net")
|
||||
.setting
|
||||
label(for="domain_youtube") Replace YouTube links with Invidious (blank to disable):
|
||||
label(for="domain_youtube") Replace YouTube links with <a href="https://github.com/iv-org/invidious">Invidious</a>/<a href="https://github.com/TeamPiped/Piped">Piped</a> (blank to disable):
|
||||
if(user_preferences.domain_youtube != '' && typeof(user_preferences.domain_youtube) != 'undefined')
|
||||
input(type="text", name="domain_youtube", id="domain_youtube", value="" + user_preferences.domain_youtube + "", placeholder="e.g. invidious.site")
|
||||
else
|
||||
input(type="text", name="domain_youtube", id="domain_youtube", placeholder="e.g. invidious.site")
|
||||
.setting
|
||||
label(for="domain_instagram") Replace Instagram links with Bibliogram (blank to disable):
|
||||
if(user_preferences.domain_instagram != '' && typeof(user_preferences.domain_instagram) != 'undefined')
|
||||
input(type="text", name="domain_instagram", id="domain_instagram", value="" + user_preferences.domain_instagram + "", placeholder="e.g. bibliogram.art")
|
||||
label(for="domain_quora") Replace Quora links with <a href="https://codeberg.org/zyachel/quetre">Quetre</a> (blank to disable):
|
||||
if(user_preferences.domain_quora != '' && typeof(user_preferences.domain_quora) != 'undefined')
|
||||
input(type="text", name="domain_quora", id="domain_quora", value="" + user_preferences.domain_quora + "", placeholder="e.g. quetre.iket.me")
|
||||
else
|
||||
input(type="text", name="domain_instagram", id="domain_instagram", placeholder="e.g. bibliogram.art")
|
||||
input(type="text", name="domain_quora", id="domain_quora", placeholder="e.g. quetre.iket.me")
|
||||
.setting
|
||||
label(for="domain_imgur") Replace Imgur links with <a href="https://codeberg.org/video-prize-ranch/rimgo">Rimgo</a> (blank to disable):
|
||||
if(user_preferences.domain_imgur != '' && typeof(user_preferences.domain_imgur) != 'undefined')
|
||||
input(type="text", name="domain_imgur", id="domain_imgur", value="" + user_preferences.domain_imgur + "", placeholder="e.g. rimgo.bcow.xyz")
|
||||
else
|
||||
input(type="text", name="domain_imgur", id="domain_imgur", placeholder="e.g. rimgo.bcow.xyz")
|
||||
legend Display
|
||||
.setting
|
||||
label(for="theme") Theme:
|
||||
|
@ -37,21 +46,37 @@ html
|
|||
option(value="white") White
|
||||
option(value="dark") Dark
|
||||
option(value="sepia") Sepia
|
||||
if(user_preferences.theme == 'white')
|
||||
option(value="nord") Nord
|
||||
else if(user_preferences.theme == 'white')
|
||||
option(value="auto") Auto
|
||||
option(value="white", selected="selected") White
|
||||
option(value="dark") Dark
|
||||
option(value="sepia") Sepia
|
||||
if(user_preferences.theme === 'dark')
|
||||
option(value="nord") Nord
|
||||
else if(user_preferences.theme === 'dark')
|
||||
option(value="auto") Auto
|
||||
option(value="white") White
|
||||
option(value="dark", selected="selected") Dark
|
||||
option(value="sepia") Sepia
|
||||
if(user_preferences.theme === 'sepia')
|
||||
option(value="nord") Nord
|
||||
else if(user_preferences.theme === 'sepia')
|
||||
option(value="auto") Auto
|
||||
option(value="white") White
|
||||
option(value="dark") Dark
|
||||
option(value="sepia", selected="selected") Sepia
|
||||
option(value="nord") Nord
|
||||
else if(user_preferences.theme === 'nord')
|
||||
option(value="auto") Auto
|
||||
option(value="white") White
|
||||
option(value="dark") Dark
|
||||
option(value="sepia") Sepia
|
||||
option(value="nord", selected="selected") Nord
|
||||
else
|
||||
option(value="auto") Auto
|
||||
option(value="white") White
|
||||
option(value="dark") Dark
|
||||
option(value="sepia") Sepia
|
||||
option(value="nord") Nord
|
||||
.setting
|
||||
label(for="flairs") Show flairs:
|
||||
if(!user_preferences.flairs || user_preferences.flairs == 'true')
|
||||
|
@ -96,6 +121,29 @@ html
|
|||
input(type="checkbox", name="show_upvoted_percentage", id="show_upvoted_percentage", checked="checked")
|
||||
else
|
||||
input(type="checkbox", name="show_upvoted_percentage", id="show_upvoted_percentage")
|
||||
.setting
|
||||
label(for="show_upvotes") Show upvotes:
|
||||
if(!user_preferences.show_upvotes || user_preferences.show_upvotes == 'true')
|
||||
input(type="checkbox", name="show_upvotes", id="show_upvotes", checked="checked")
|
||||
else
|
||||
input(type="checkbox", name="show_upvotes", id="show_upvotes")
|
||||
.setting
|
||||
label(for="prefer_frontpage") Prefer reddit-style frontpage as homepage:
|
||||
if ((!instance_config.clean_homepage && !user_preferences.prefer_frontpage) || user_preferences.prefer_frontpage == 'true')
|
||||
input(type="checkbox", name="prefer_frontpage", id="prefer_frontpage", checked="checked")
|
||||
else
|
||||
input(type="checkbox", name="prefer_frontpage", id="prefer_frontpage")
|
||||
.setting
|
||||
label(for="default_comment_sort") Default comment sorting:
|
||||
select(id="default_comment_sort", name="default_comment_sort")
|
||||
-
|
||||
let default_comment_sort_html = ''
|
||||
let user_default_sort = user_preferences.default_comment_sort || 'best'
|
||||
|
||||
for(let key of comment_sort_values) {
|
||||
default_comment_sort_html += `<option value="${key}" ${(user_default_sort == key ? "selected" : "")}>${key == 'qa' ? 'Q&A' : key}</option>`
|
||||
}
|
||||
!= default_comment_sort_html
|
||||
legend Media
|
||||
.setting
|
||||
label(for="videos_muted") Mute videos by default:
|
||||
|
@ -111,6 +159,12 @@ html
|
|||
input(type="checkbox", name="videos_muted", id="videos_muted", checked="checked")
|
||||
else
|
||||
input(type="checkbox", name="videos_muted", id="videos_muted")
|
||||
.setting
|
||||
label(for="show_large_gallery_images") Show large gallery images with captions:
|
||||
if (user_preferences.show_large_gallery_images == 'true')
|
||||
input(type="checkbox", name="show_large_gallery_images", id="show_large_gallery_images", checked="checked")
|
||||
else
|
||||
input(type="checkbox", name="show_large_gallery_images", id="show_large_gallery_images")
|
||||
small(class="notice") Preferences are stored client-side using cookies without any personal information.
|
||||
br
|
||||
input(type="submit", value="Save preferences")
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title privacy policy - teddit
|
||||
meta(property='og:title', content='privacy policy - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title saved
|
||||
meta(property='og:title', content='saved - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
|
@ -3,8 +3,12 @@ html
|
|||
head
|
||||
if no_query
|
||||
title search teddit
|
||||
meta(property='og:title', content='search - teddit')
|
||||
else
|
||||
title search results for #{q}
|
||||
meta(property='og:title', content='search results for ' + q + ' - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
@ -140,8 +144,8 @@ html
|
|||
include components/link.pug
|
||||
if json.before || json.after
|
||||
.view-more-links
|
||||
if json.before && !subreddit_front
|
||||
a(href="?q=" + q + "&restrict_sr=" + restrict_sr + "&nsfw=" + nsfw + "&before=" + json.before + "") ‹ prev
|
||||
if json.before
|
||||
a(href="?q=" + q + "&restrict_sr=" + restrict_sr + "&nsfw=" + nsfw + "&before=" + json.before + "" + (sortby === "new" && sortby ? "&" : "&sort=" + sortby + "&") + (!past ? "" : "t=" + past)) ‹ prev
|
||||
if json.after
|
||||
a(href="?q=" + q + "&restrict_sr=" + restrict_sr + "&nsfw=" + nsfw + "&after=" + json.after + "") next ›
|
||||
a(href="?q=" + q + "&restrict_sr=" + restrict_sr + "&nsfw=" + nsfw + "&after=" + json.after + "" + (sortby === "new" && sortby ? "&" : "&sort=" + sortby + "&") + (!past ? "" : "t=" + past)) next ›
|
||||
include includes/footer.pug
|
||||
|
|
|
@ -2,6 +2,10 @@ doctype html
|
|||
html
|
||||
head
|
||||
title /r/#{subreddit}
|
||||
meta(property='og:title', content='/r/' + subreddit)
|
||||
if subreddit_about
|
||||
meta(property='og:description', content='' + unescape(subreddit_about.public_description_html, user_preferences))
|
||||
include includes/meta_default.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
|
@ -2,6 +2,8 @@ doctype html
|
|||
html
|
||||
head
|
||||
title wiki /r/#{subreddit}
|
||||
meta(property='og:title', content='wiki /r/' + subreddit)
|
||||
include includes/meta_default.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
|
@ -2,6 +2,9 @@ doctype html
|
|||
html
|
||||
head
|
||||
title subreddits - explore
|
||||
meta(property='og:title', content='explore subreddits - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/meta_description.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
|
@ -2,6 +2,8 @@ doctype html
|
|||
html
|
||||
head
|
||||
title overview for #{data.username}
|
||||
meta(property='og:title', content='u/' + data.username + ' - teddit')
|
||||
include includes/meta_default.pug
|
||||
include includes/head.pug
|
||||
body(class=""+ (user_preferences.theme === 'auto' ? 'dark' : user_preferences.theme) + "")
|
||||
include includes/topbar.pug
|
||||
|
|
Loading…
Reference in New Issue