Merge branch 'main' into main

This commit is contained in:
Anshuman Kumar 2023-01-02 11:46:26 +00:00
commit 0969d694db
10 changed files with 933 additions and 1993 deletions

View File

@ -12,4 +12,6 @@ COPY config.js.template ./config.js
RUN find ./static/ -type d -exec chmod -R 777 {} \; RUN find ./static/ -type d -exec chmod -R 777 {} \;
EXPOSE 8080
CMD npm start CMD npm start

View File

@ -201,11 +201,15 @@ You can also run teddit from a process manager like [pm2](https://www.npmjs.com/
``` ```
## To run: ## To run:
npm install pm2 -g npm install pm2 -g
pm2 start app.js pm2 start app.js --name teddit
## To run on startup: ## To run on startup:
pm2 startup pm2 startup
pm2 save 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/), and in particular the section on waiting for your machine to connect to its network. 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.

View File

@ -73,7 +73,7 @@ module.exports = function(fetch) {
}) })
} }
this.redditApiGETHeaders = function() { 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) if(!config.use_reddit_oauth)
return { headers: { cookie: cookies }, method: 'GET' } return { headers: { cookie: cookies }, method: 'GET' }

View File

@ -1,5 +1,6 @@
const compilePostComments = require('./compilePostComments.js')(); const compilePostComments = require('./compilePostComments.js')();
const procPostMedia = require('./processPostMedia.js')(); const procPostMedia = require('./processPostMedia.js')();
const config = require('../config');
async function processReplies(data, post_id, depth, user_preferences) { async function processReplies(data, post_id, depth, user_preferences) {
let return_replies = []; let return_replies = [];
@ -399,8 +400,141 @@ async function finalizeJsonPost(
return { post_data: post_data, comments: comments_html }; 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 = { module.exports = {
processReplies, processReplies,
processJsonPost, processJsonPost,
finalizeJsonPost, finalizeJsonPost,
processJsonPostList,
getPostItem
}; };

View File

@ -64,4 +64,15 @@ async function processSubredditAbout(subreddit, redis, fetch, RedditAPI) {
} }
} }
module.exports = processSubredditAbout; async function processJsonSubredditAbout(json, parsed) {
if (!parsed) {
json = JSON.parse(json);
}
return returnRelevantKeys(json);
}
module.exports = {
processSubredditAbout,
processJsonSubredditAbout
};

View File

@ -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&amp;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));
}
}
};
};

View File

@ -1,4 +1,8 @@
const processJsonSubreddit = require('../processJsonSubreddit'); 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 () { module.exports = function () {
const config = require('../../config'); const config = require('../../config');
@ -27,93 +31,10 @@ module.exports = function () {
if (api_type === 'rss') { if (api_type === 'rss') {
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http'; let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http';
let items = ''; let items = '';
for (var i = 0; i < json.data.children.length; i++) { for (var i = 0; i < json.data.children.length; i++) {
let link = json.data.children[i].data; let post = json.data.children[i].data;
let thumbnail = ''; items += await getPostItem(post, req, protocol);
let post_image = '';
let is_self_link = false;
let valid_reddit_self_domains = ['reddit.com'];
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);
}
}
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}`;
}
}
}
}
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 r_subreddit = '/r/' + subreddit;
@ -149,43 +70,185 @@ module.exports = function () {
req.cookies req.cookies
); );
let protocol = config.https_enabled || config.api_force_https ? 'https' : 'http'; await processJsonPostList(processed_json.links, mode);
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;
if (link.domain) { return res.end(JSON.stringify(processed_json));
let tld = link.domain.split('self.'); }
if (tld.length > 1) { }
if (!tld[1].includes('.')) { };
is_self_link = true; this.handleTedditApiSubredditAbout = async (
link.url = teddifyUrl(link.url); json,
} res,
} from,
if ( api_target
config.valid_media_domains.includes(link.domain) || ) => {
valid_reddit_self_domains.includes(link.domain) if (!config.api_enabled) {
) { res.setHeader('Content-Type', 'application/json');
is_self_link = true; let msg = {
link.url = teddifyUrl(link.url); 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 (api_target === 'reddit') {
if (link.images.thumb !== 'self') { return res.end(JSON.stringify(json));
link.images.thumb = `${protocol}://${config.domain}${link.images.thumb}`; } else {
} let subreddit_about = await processJsonSubredditAbout(
} json,
true
);
if (mode === 'light') { return res.end(JSON.stringify(subreddit_about));
link.selftext_html = null; }
} };
} 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));
}
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}&amp;api&amp;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}&amp;api&amp;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)); return res.end(JSON.stringify(processed_json));
} }

1818
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
"dependencies": { "dependencies": {
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"express": "^4.17.1", "express": "^4.18.2",
"helmet": "^4.6.0", "helmet": "^4.6.0",
"https-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0",
"minizlib": "^2.1.2", "minizlib": "^2.1.2",

View File

@ -6,16 +6,28 @@ const {
processJsonPost, processJsonPost,
finalizeJsonPost, finalizeJsonPost,
} = require('../inc/processJsonPost.js'); } = require('../inc/processJsonPost.js');
const processSubredditAbout = require('../inc/processSubredditAbout.js'); const {
processSubredditAbout
} = require('../inc/processSubredditAbout.js');
const processSearchResults = require('../inc/processSearchResults.js'); const processSearchResults = require('../inc/processSearchResults.js');
const processJsonSubreddit = require('../inc/processJsonSubreddit.js'); const processJsonSubreddit = require('../inc/processJsonSubreddit.js');
const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')(); const tedditApiSubreddit = require('../inc/teddit_api/handleSubreddit.js')();
const tedditApiPost = require('../inc/teddit_api/handlePost.js')();
const processMoreComments = require('../inc/processMoreComments.js'); const processMoreComments = require('../inc/processMoreComments.js');
const processJsonSubredditsExplore = require('../inc/processSubredditsExplore.js'); const processJsonSubredditsExplore = require('../inc/processSubredditsExplore.js');
subredditRoutes.get('/r/:subreddit/search', (req, res, next) => { subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
let subreddit = req.params.subreddit; let subreddit = req.params.subreddit;
let q = req.query.q; 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') { if (typeof q === 'undefined') {
return res.render('search', { return res.render('search', {
@ -62,7 +74,7 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
count = ''; count = '';
} }
let key = `search:${subreddit}:${q}:${restrict_sr}:${sortby}:${past}:${after}:${before}:${nsfw}`; let key = `search:${subreddit}:${q}:${restrict_sr}:${sortby}:${past}:${after}:${before}:${nsfw}:raw_json:${raw_json}`;
redis.get(key, (error, json) => { redis.get(key, (error, json) => {
if (error) { if (error) {
console.error('Error getting the search key from redis.', error); console.error('Error getting the search key from redis.', error);
@ -75,32 +87,46 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
if (json) { if (json) {
console.log('Got search key from redis.'); console.log('Got search key from redis.');
(async () => { (async () => {
let processed_json = await processSearchResults( if (api_req) {
json, return handleTedditApiSubredditSearch(
false, json,
after, req,
before, res,
req.cookies 'redis',
); api_type,
return res.render('search', { api_target,
json: processed_json, subreddit,
no_query: false, q,
q: q, api_mode
restrict_sr: restrict_sr, );
nsfw: nsfw, } else {
subreddit: subreddit, let processed_json = await processSearchResults(
sortby: sortby, json,
past: past, false,
user_preferences: req.cookies, after,
instance_config: config, before,
}); req.cookies
);
return res.render('search', {
json: processed_json,
no_query: false,
q: q,
restrict_sr: restrict_sr,
nsfw: nsfw,
subreddit: subreddit,
sortby: sortby,
past: past,
user_preferences: req.cookies,
instance_config: config,
});
}
})(); })();
} else { } else {
let url = ''; let url = '';
if (config.use_reddit_oauth) 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}${count}${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 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}${count}${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()) fetch(encodeURI(url), redditApiGETHeaders())
.then((result) => { .then((result) => {
if (result.status === 200) { if (result.status === 200) {
@ -137,25 +163,39 @@ subredditRoutes.get('/r/:subreddit/search', (req, res, next) => {
} else { } else {
console.log('Fetched search results from Reddit.'); console.log('Fetched search results from Reddit.');
(async () => { (async () => {
let processed_json = await processSearchResults( if (api_req) {
json, return handleTedditApiSubredditSearch(
true, json,
after, req,
before, res,
req.cookies 'from_online',
); api_type,
return res.render('search', { api_target,
no_query: false, subreddit,
json: processed_json, q,
q: q, api_mode
restrict_sr: restrict_sr, );
nsfw: nsfw, } else {
subreddit: subreddit, let processed_json = await processSearchResults(
sortby: sortby, json,
past: past, true,
user_preferences: req.cookies, after,
instance_config: config, before,
}); req.cookies
);
return res.render('search', {
no_query: false,
json: processed_json,
q: q,
restrict_sr: restrict_sr,
nsfw: nsfw,
subreddit: subreddit,
sortby: sortby,
past: past,
user_preferences: req.cookies,
instance_config: config,
});
}
})(); })();
} }
} }
@ -182,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( subredditRoutes.get(
'/r/:subreddit/wiki/:page?/:sub_page?', '/r/:subreddit/wiki/:page?/:sub_page?',
(req, res, next) => { (req, res, next) => {
@ -605,6 +746,14 @@ subredditRoutes.get(
let viewing_comment = false; let viewing_comment = false;
let comment_ids = req.query.comment_ids; let comment_ids = req.query.comment_ids;
let context = parseInt(req.query.context); 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) { if (req.params.comment_id) {
comment_id = `${req.params.comment_id}/`; comment_id = `${req.params.comment_id}/`;
@ -637,7 +786,7 @@ subredditRoutes.get(
let comments_url = `/r/${subreddit}/comments/${id}/${snippet}/${comment_id}`; let comments_url = `/r/${subreddit}/comments/${id}/${snippet}/${comment_id}`;
let post_url = `/r/${subreddit}/comments/${id}/${snippet}/`; 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) => { redis.get(comments_key, (error, json) => {
if (error) { if (error) {
@ -654,57 +803,68 @@ subredditRoutes.get(
if (json) { if (json) {
console.log(`Got ${comments_url} key from redis.`); console.log(`Got ${comments_url} key from redis.`);
(async () => { (async () => {
let parsed = false; if (api_req) {
let more_comments = null; return handleTedditApiPost(
if (comment_ids) { json,
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`; req,
more_comments = await processMoreComments( res,
fetch, 'redis',
redis, api_type,
post_url, api_target
comment_ids,
id
); );
} else {
let parsed = false;
let more_comments = null;
if (comment_ids) {
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`;
more_comments = await processMoreComments(
fetch,
redis,
post_url,
comment_ids,
id
);
if (more_comments === false) { if (more_comments === false) {
return res.redirect(post_url); return res.redirect(post_url);
} else { } else {
json = JSON.parse(json); json = JSON.parse(json);
json[1].data.children = more_comments; json[1].data.children = more_comments;
parsed = true; parsed = true;
}
} }
}
let processed_json = await processJsonPost(json, parsed, req.cookies); let processed_json = await processJsonPost(json, parsed, req.cookies);
let finalized_json = await finalizeJsonPost( let finalized_json = await finalizeJsonPost(
processed_json, processed_json,
id, id,
post_url, post_url,
more_comments, more_comments,
viewing_comment, viewing_comment,
req.cookies req.cookies
); );
return res.render('post', { return res.render('post', {
post: finalized_json.post_data, post: finalized_json.post_data,
comments: finalized_json.comments, comments: finalized_json.comments,
viewing_comment: viewing_comment, viewing_comment: viewing_comment,
post_url: post_url, post_url: post_url,
subreddit: subreddit, subreddit: subreddit,
sortby: sortby, sortby: sortby,
user_preferences: req.cookies, user_preferences: req.cookies,
instance_nsfw_enabled: config.nsfw_enabled, instance_nsfw_enabled: config.nsfw_enabled,
instance_videos_muted: config.videos_muted, instance_videos_muted: config.videos_muted,
post_media_max_heights: config.post_media_max_heights, post_media_max_heights: config.post_media_max_heights,
redis_key: comments_key, redis_key: comments_key,
instance_config: config, instance_config: config,
}); });
}
})(); })();
} else { } else {
let url = ''; let url = '';
if (config.use_reddit_oauth) 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 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()) fetch(encodeURI(url), redditApiGETHeaders())
.then((result) => { .then((result) => {
@ -730,51 +890,62 @@ subredditRoutes.get(
`Fetched the JSON from reddit.com${comments_url}.` `Fetched the JSON from reddit.com${comments_url}.`
); );
(async () => { (async () => {
let more_comments = null; if (api_req) {
if (comment_ids) { return handleTedditApiPost(
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`; json,
more_comments = await processMoreComments( req,
fetch, res,
redis, 'from_online',
post_url, api_type,
comment_ids, api_target
id
); );
} else {
let more_comments = null;
if (comment_ids) {
let key = `${post_url}:morechildren:comment_ids:${comment_ids}`;
more_comments = await processMoreComments(
fetch,
redis,
post_url,
comment_ids,
id
);
if (more_comments === false) { if (more_comments === false) {
return res.redirect(post_url); return res.redirect(post_url);
} else { } else {
json[1].data.children = more_comments; json[1].data.children = more_comments;
}
} }
}
let processed_json = await processJsonPost( let processed_json = await processJsonPost(
json, json,
true, true,
req.cookies req.cookies
); );
let finalized_json = await finalizeJsonPost( let finalized_json = await finalizeJsonPost(
processed_json, processed_json,
id, id,
post_url, post_url,
more_comments, more_comments,
viewing_comment, viewing_comment,
req.cookies req.cookies
); );
return res.render('post', { return res.render('post', {
post: finalized_json.post_data, post: finalized_json.post_data,
comments: finalized_json.comments, comments: finalized_json.comments,
viewing_comment: viewing_comment, viewing_comment: viewing_comment,
post_url: post_url, post_url: post_url,
subreddit: subreddit, subreddit: subreddit,
sortby: sortby, sortby: sortby,
user_preferences: req.cookies, user_preferences: req.cookies,
instance_nsfw_enabled: config.nsfw_enabled, instance_nsfw_enabled: config.nsfw_enabled,
instance_videos_muted: config.videos_muted, instance_videos_muted: config.videos_muted,
post_media_max_heights: config.post_media_max_heights, post_media_max_heights: config.post_media_max_heights,
redis_key: comments_key, redis_key: comments_key,
instance_config: config, instance_config: config,
}); });
}
})(); })();
} }
} }
@ -839,6 +1010,14 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
let before = req.query.before; let before = req.query.before;
let sortby = req.params.sort; let sortby = req.params.sort;
let searching = false; 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) { if (!after) {
after = ''; after = '';
@ -860,12 +1039,12 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
sortby = ''; sortby = '';
} }
let key = `subreddits:sort:${sortby}${d}`; let key = `subreddits:sort:${sortby}${d}:raw_json:${raw_json}`;
if (sortby === 'search') { if (sortby === 'search') {
if (typeof q == 'undefined' || q == '') return res.redirect('/subreddits'); 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; searching = true;
} }
@ -881,48 +1060,60 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
if (json) { if (json) {
console.log(`Got subreddits key from redis.`); console.log(`Got subreddits key from redis.`);
(async () => { (async () => {
let processed_json = await processJsonSubredditsExplore( if (api_req) {
json, return handleTedditApiSubredditsExplore(
'redis', json,
null, req,
req.cookies res,
); 'redis',
if (!processed_json.error) { api_type,
return res.render('subreddits_explore', { api_target,
json: processed_json, q
sortby: sortby, );
after: after,
before: before,
q: q,
nsfw: nsfw,
searching: searching,
subreddits_front: !before && !after ? true : false,
user_preferences: req.cookies,
instance_nsfw_enabled: config.nsfw_enabled,
instance_config: config,
});
} else { } else {
return res.render('subreddits_explore', { let processed_json = await processJsonSubredditsExplore(
json: null, json,
error: true, 'redis',
data: processed_json, null,
user_preferences: req.cookies, req.cookies
instance_config: config, );
}); if (!processed_json.error) {
return res.render('subreddits_explore', {
json: processed_json,
sortby: sortby,
after: after,
before: before,
q: q,
nsfw: nsfw,
searching: searching,
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', {
json: null,
error: true,
data: processed_json,
user_preferences: req.cookies,
instance_config: config,
});
}
} }
})(); })();
} else { } else {
let url = ''; let url = '';
if (config.use_reddit_oauth) { if (config.use_reddit_oauth) {
if (!searching) 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 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 { } else {
if (!searching) 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 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()) fetch(encodeURI(url), redditApiGETHeaders())
@ -946,25 +1137,37 @@ subredditRoutes.get('/subreddits/:sort?', (req, res, next) => {
} else { } else {
console.log(`Fetched the JSON from reddit.com/subreddits.`); console.log(`Fetched the JSON from reddit.com/subreddits.`);
(async () => { (async () => {
let processed_json = await processJsonSubredditsExplore( if (api_req) {
json, return handleTedditApiSubredditsExplore(
'from_online', json,
null, req,
req.cookies res,
); 'from_online',
return res.render('subreddits_explore', { api_type,
json: processed_json, api_target,
sortby: sortby, q
after: after, );
before: before, } else {
q: q, let processed_json = await processJsonSubredditsExplore(
nsfw: nsfw, json,
searching: searching, 'from_online',
subreddits_front: !before && !after ? true : false, null,
user_preferences: req.cookies, req.cookies
instance_nsfw_enabled: config.nsfw_enabled, );
instance_config: config, return res.render('subreddits_explore', {
}); json: processed_json,
sortby: sortby,
after: after,
before: before,
q: q,
nsfw: nsfw,
searching: searching,
subreddits_front: !before && !after ? true : false,
user_preferences: req.cookies,
instance_nsfw_enabled: config.nsfw_enabled,
instance_config: config,
});
}
})(); })();
} }
}); });