diff --git a/README.md b/README.md index 6aeee72..8deb236 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Community instances: ## TODO -* Subreddit wikis * User trophies * "other discussions" feature * "Open on reddit" links diff --git a/config.js.template b/config.js.template index 6e078f8..be8cac8 100644 --- a/config.js.template +++ b/config.js.template @@ -37,7 +37,8 @@ const config = { user: 600, searches: 600, sidebar: 60 * 60 * 24 * 7, // 7 days - shorts: 60 * 60 * 24 * 31 + shorts: 60 * 60 * 24 * 31, + wikis: 60* 60 * 24 * 7 }, 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', 'thumbs.gfycat.com', 'i.ytimg.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.` diff --git a/routes.js b/routes.js index 174a695..7eb3e63 100644 --- a/routes.js +++ b/routes.js @@ -346,6 +346,81 @@ module.exports = (app, redis, fetch, RedditAPI) => { }) }) + app.get('/r/:subreddit/wiki/:page?', (req, res, next) => { + let subreddit = req.params.subreddit + let page = req.params.page + + if(!page) + page = 'index' + + let key = `${subreddit.toLowerCase()}:wiki:page:${page}` + redis.get(key, (error, json) => { + if(error) { + console.error(`Error getting the ${subreddit} wiki key from redis.`, error) + return res.render('index', { json: null, user_preferences: req.cookies }) + } + if(json) { + console.log(`Got /r/${subreddit} wiki key from redis.`) + json = JSON.parse(json) + return res.render('subreddit_wiki', { + content_html: unescape(json.data.content_html), + subreddit: subreddit, + user_preferences: req.cookies + }) + } else { + let url = '' + if(config.use_reddit_oauth) + url = `https://oauth.reddit.com/r/${subreddit}/wiki/${page}?api_type=json` + else + url = `https://reddit.com/r/${subreddit}/wiki/${page}.json?api_type=json` + fetch(encodeURI(url), redditApiGETHeaders()) + .then(result => { + if(result.status === 200) { + result.json() + .then(json => { + redis.setex(key, config.setexs.wikis, JSON.stringify(json), (error) => { + if(error) { + console.error(`Error setting the ${subreddit} wiki key to redis.`, error) + return res.render('subreddit', { json: null, user_preferences: req.cookies }) + } else { + console.log(`Fetched the JSON from reddit.com/r/${subreddit}/wiki.`) + return res.render('subreddit_wiki', { + content_html: unescape(json.data.content_html), + subreddit: subreddit, + user_preferences: req.cookies + }) + } + }) + }) + } else { + if(result.status === 404) { + console.log('404 – Subreddit wiki 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('index', { + json: null, + http_status_code: result.status, + user_preferences: req.cookies + }) + } + }).catch(error => { + console.error(`Error fetching the JSON file from reddit.com/r/${subreddit}/wiki.`, error) + }) + } + }) + }) + + app.get('/r/:subreddit/w/:page?', (req, res, next) => { + /* "w" is a shorturl for wikis for example https://old.reddit.com/r/privacytoolsIO/w/index */ + let subreddit = req.params.subreddit + let page = req.params.page + if(!page) + page = 'index' + return res.redirect(`/r/${subreddit}/wiki/${page}`) + }) + app.get('/r/:subreddit/:sort?', (req, res, next) => { let subreddit = req.params.subreddit let sortby = req.params.sort diff --git a/static/css/styles.css b/static/css/styles.css index afd819c..6cb2736 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -1408,6 +1408,146 @@ code { font-size:1em; line-height:1.25em; } +/* REDDIT WIKI STYLES */ +.wiki-content { + margin:15px; + float: left; + width: calc(100% - 30px); + font-size: 0.8rem; +} +.wiki-content .pagelisting { + font-size:1.2em; + font-weight:bold; + color:black; + padding-left:25px +} +.wiki-content .pagelisting ul { + list-style:disc; + padding:2px; + padding-left:10px +} +.wiki-content .description { + padding-bottom:5px +} +.wiki-content .description h2 { + color:#222 +} +.wiki-content .wikirevisionlisting .generic-table { + width:100% +} +.wiki-content .wikirevisionlisting table tr td { + padding-right:15px +} +.wiki-content .wikirevisionlisting .revision.deleted { + opacity:.5; + text-decoration:line-through +} +.wiki-content .wikirevisionlisting .revision.hidden { + opacity:.5 +} +.wiki-content .wikirevisionlisting .revision.hidden td { + opacity:inherit +} +.wiki-content .wiki.md { + max-width:none +} +.wiki-content .wiki>.toc>ul { + float:right; + padding:11px 22px; + margin:0 0 11px 22px; + border:1px solid #8D9CAA; + list-style:none; + max-width:300px +} +.wiki-content .wiki>.toc>ul ul { + margin:4px 0; + padding-left:22px; + border-left:1px dotted #cce; + list-style:none +} +.wiki-content .wiki>.toc>ul li { + margin:0 +} +.wiki-content .fancy-settings .toggle { + display:inline-block; + padding-right:15px +} +.wiki-content #wiki_revision_reason { + padding:2px; + margin-left:0; + width:100% +} +.wiki-content .wiki_button { + padding:2px +} +.wiki-content .throbber { + margin-bottom:-5px +} +.wiki-content .discussionlink { + display:inline-block; + margin-left:15px; + padding-right:50px; + margin-top:5px +} +.wiki-content .discussionlink a { + padding-left:15px +} +.wiki-content .markhelp { + max-width:500px; + font-size:1.2em; + padding:4px; + margin:5px 0 +} +.wiki-page .wikititle { + margin-left:15px; + color:#666; + display:inline; + vertical-align:middle +} +.wiki-page .wikititle strong { + font-weight:bold +} +.wiki-page .pageactions { + display:inline-block; + font-size:larger; + margin-left:25px; + border-radius:5px; + border:1px solid #8D9CAA; + vertical-align:middle +} +.wiki-page .pageactions .wikiaction { + display:inline-block; + margin:2px; + padding-top:2px; + padding-bottom:3px; + border-radius:3px; + padding-right:10px; + padding-left:10px +} +.wiki-page .pageactions .wikiaction:hover { + background-color:#CEE3F8 +} +.wiki-page .pageactions .wikiaction-current:hover { + background-color:#5F99CF +} +.wiki-page .pageactions .wikiaction-current { + color:white; + background-color:#5F99CF +} +.wiki-page .source { + width:100%; + display:none +} +.wiki-page .toggle-source { + float:right +} +.wiki-page-config-automoderator #editform textarea { + font-family:"Bitstream Vera Sans Mono",Consolas,monospace +} +.wiki-page-config-automoderator .wiki-page-content pre { + word-wrap:break-word; + white-space:pre-wrap +} /* 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; diff --git a/views/subreddit_wiki.pug b/views/subreddit_wiki.pug new file mode 100644 index 0000000..836d2c4 --- /dev/null +++ b/views/subreddit_wiki.pug @@ -0,0 +1,21 @@ +doctype html +html + head + title wiki /r/#{subreddit} + include includes/head.pug + body(class=""+ user_preferences.theme +"") + include includes/topbar.pug + if json === null + h1 Error occured + if error + p Error: #{JSON.stringify(json.error_data)} + else + header + a(href="/", class="main") + h1 teddit + .bottom + a(href="/r/" + subreddit + "", class="subreddit") + h2 wiki - #{subreddit} + .wiki-content + != content_html + include includes/footer.pug