add teddit api support for subreddits

This commit is contained in:
teddit 2020-12-19 20:52:22 +01:00
parent 36bee6ef19
commit 8a78051534
5 changed files with 218 additions and 45 deletions

View File

@ -2,6 +2,7 @@ const config = {
domain: process.env.DOMAIN || '127.0.0.1', // Or for example 'teddit.net' domain: process.env.DOMAIN || '127.0.0.1', // Or for example 'teddit.net'
reddit_app_id: process.env.REDDIT_APP_ID || 'H6-HjZ5pUPjaFQ', // You should obtain your own 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. reddit_app_id: process.env.REDDIT_APP_ID || 'H6-HjZ5pUPjaFQ', // You should obtain your own 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.
cert_dir: process.env.CERT_DIR || '', // For example '/home/teddit/letsencrypt/live/teddit.net', if you are using https. No trailing slash. cert_dir: process.env.CERT_DIR || '', // For example '/home/teddit/letsencrypt/live/teddit.net', if you are using https. No trailing slash.
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, video_enabled: process.env.VIDEO_ENABLED !== "true" || true,
redis_enabled: process.env.REDIS_ENABLED !== "true" || true, // If disabled, does not cache Reddit API calls redis_enabled: process.env.REDIS_ENABLED !== "true" || true, // If disabled, does not cache Reddit API calls
redis_host: process.env.REDIS_HOST || '127.0.0.1', redis_host: process.env.REDIS_HOST || '127.0.0.1',

View File

@ -0,0 +1,137 @@
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))
}
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 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}`
}
}
}
link.permalink = `${protocol}://${config.domain}${link.permalink}`
if(is_self_link)
link.url = link.permalink
items += `
<item>
<title>${link.title}</title>
<author>${link.author}</author>
<created>${link.created}</created>
<domain>${link.domain}</domain>
<id>${link.id}</id>
<thumbnail>${thumbnail}</thumbnail>
<permalink>${link.permalink}</permalink>
<url>${link.url}</url>
<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"?>
<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&amp;type=rss" rel="self" type="application/rss+xml" />
<title>${title}</title>
<link>${link}</link>
<description>Subreddit feed for: ${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 processJsonSubreddit(_json, from)
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
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}`
}
}
}
return res.end(JSON.stringify(processed_json))
}
}
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "teddit", "name": "teddit",
"version": "0.0.3", "version": "0.0.5",
"description": "A free and open source alternative Reddit front-end focused on privacy.", "description": "A free and open source alternative Reddit front-end focused on privacy.",
"homepage": "https://teddit.net", "homepage": "https://teddit.net",
"bugs": { "bugs": {

121
routes.js
View File

@ -8,6 +8,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
let processUser = require('./inc/processJsonUser.js')(); let processUser = require('./inc/processJsonUser.js')();
let processSearches = require('./inc/processSearchResults.js')(); let processSearches = require('./inc/processSearchResults.js')();
let processSidebar = require('./inc/processSubredditSidebar.js')(); let processSidebar = require('./inc/processSubredditSidebar.js')();
let tedditApiSubreddit = require('./inc/teddit_api/handleSubreddit.js')();
app.get('/about', (req, res, next) => { app.get('/about', (req, res, next) => {
return res.render('about', { user_preferences: req.cookies }) return res.render('about', { user_preferences: req.cookies })
@ -59,6 +60,10 @@ module.exports = (app, redis, fetch, RedditAPI) => {
let before = req.query.before let before = req.query.before
let after = req.query.after let after = req.query.after
let sortby = req.params.sort let sortby = req.params.sort
let api_req = req.query.api
let api_type = req.query.type
let api_target = req.query.target
let d = `&after=${after}` let d = `&after=${after}`
if(before) { if(before) {
d = `&before=${before}` d = `&before=${before}`
@ -88,6 +93,11 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} }
} }
if(req.query.hasOwnProperty('api'))
api_req = true
else
api_req = false
let key = `/after:${after}:before:${before}:sort:${sortby}:past:${past}` let key = `/after:${after}:before:${before}:sort:${sortby}:past:${past}`
redis.get(key, (error, json) => { redis.get(key, (error, json) => {
if(error) { if(error) {
@ -97,13 +107,17 @@ module.exports = (app, redis, fetch, RedditAPI) => {
if(json) { if(json) {
console.log('Got frontpage key from redis.'); console.log('Got frontpage key from redis.');
(async () => { (async () => {
let processed_json = await processJsonSubreddit(json, 'redis') if(api_req) {
return res.render('index', { return handleTedditApiSubreddit(json, req, res, 'redis', api_type, api_target, '/')
json: processed_json, } else {
sortby: sortby, let processed_json = await processJsonSubreddit(json, 'redis')
past: past, return res.render('index', {
user_preferences: req.cookies json: processed_json,
}) sortby: sortby,
past: past,
user_preferences: req.cookies
})
}
})() })()
} else { } else {
fetch(encodeURI(`https://oauth.reddit.com/${sortby}?api_type=json&g=GLOBAL&t=${past}${d}`), redditApiGETHeaders()) fetch(encodeURI(`https://oauth.reddit.com/${sortby}?api_type=json&g=GLOBAL&t=${past}${d}`), redditApiGETHeaders())
@ -118,13 +132,17 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else { } else {
console.log('Fetched the frontpage from reddit API.'); console.log('Fetched the frontpage from reddit API.');
(async () => { (async () => {
let processed_json = await processJsonSubreddit(json, 'from_online') if(api_req) {
return res.render('index', { return handleTedditApiSubreddit(json, req, res, 'from_online', api_type, api_target, '/')
json: processed_json, } else {
sortby: sortby, let processed_json = await processJsonSubreddit(json, 'from_online')
past: past, return res.render('index', {
user_preferences: req.cookies json: processed_json,
}) sortby: sortby,
past: past,
user_preferences: req.cookies
})
}
})() })()
} }
}) })
@ -313,6 +331,15 @@ module.exports = (app, redis, fetch, RedditAPI) => {
let past = req.query.t let past = req.query.t
let before = req.query.before let before = req.query.before
let after = req.query.after let after = req.query.after
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 d = `&after=${after}` let d = `&after=${after}`
if(before) { if(before) {
d = `&before=${before}` d = `&before=${before}`
@ -351,25 +378,29 @@ module.exports = (app, redis, fetch, RedditAPI) => {
if(json) { if(json) {
console.log(`Got /r/${subreddit} key from redis.`); console.log(`Got /r/${subreddit} key from redis.`);
(async () => { (async () => {
let processed_json = await processJsonSubreddit(json, 'redis') if(api_req) {
let sidebar_data = await processSubredditSidebar(subreddit, redis, fetch, RedditAPI) return handleTedditApiSubreddit(json, req, res, 'redis', api_type, api_target, subreddit)
if(!processed_json.error) {
return res.render('subreddit', {
json: processed_json,
subreddit: subreddit,
sidebar_data: sidebar_data,
subreddit_front: (!before && !after) ? true : false,
sortby: sortby,
past: past,
user_preferences: req.cookies
})
} else { } else {
return res.render('subreddit', { let processed_json = await processJsonSubreddit(json, 'redis')
json: null, let sidebar_data = await processSubredditSidebar(subreddit, redis, fetch, RedditAPI)
error: true, if(!processed_json.error) {
data: processed_json, return res.render('subreddit', {
user_preferences: req.cookies json: processed_json,
}) subreddit: subreddit,
sidebar_data: sidebar_data,
subreddit_front: (!before && !after) ? true : false,
sortby: sortby,
past: past,
user_preferences: req.cookies
})
} else {
return res.render('subreddit', {
json: null,
error: true,
data: processed_json,
user_preferences: req.cookies
})
}
} }
})() })()
} else { } else {
@ -385,17 +416,21 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else { } else {
console.log(`Fetched the JSON from reddit.com/r/${subreddit}.`); console.log(`Fetched the JSON from reddit.com/r/${subreddit}.`);
(async () => { (async () => {
let processed_json = await processJsonSubreddit(json, 'from_online') if(api_req) {
let sidebar_data = await processSubredditSidebar(subreddit, redis, fetch, RedditAPI) return handleTedditApiSubreddit(json, req, res, 'from_online', api_type, api_target, subreddit)
return res.render('subreddit', { } else {
json: processed_json, let processed_json = await processJsonSubreddit(json, 'from_online')
subreddit: subreddit, let sidebar_data = await processSubredditSidebar(subreddit, redis, fetch, RedditAPI)
sidebar_data: sidebar_data, return res.render('subreddit', {
subreddit_front: (!before && !after) ? true : false, json: processed_json,
sortby: sortby, subreddit: subreddit,
past: past, sidebar_data: sidebar_data,
user_preferences: req.cookies subreddit_front: (!before && !after) ? true : false,
}) sortby: sortby,
past: past,
user_preferences: req.cookies
})
}
})() })()
} }
}) })

View File

@ -24,4 +24,4 @@ html
.bottom .bottom
a(href="https://en.wikipedia.org/wiki/Piratbyr%C3%A5n#Kopimi", target="_blank") a(href="https://en.wikipedia.org/wiki/Piratbyr%C3%A5n#Kopimi", target="_blank")
img(src="kopimi.gif") img(src="kopimi.gif")
p.version v.0.0.3 p.version v.0.0.5