diff --git a/inc/processJsonSubreddit.js b/inc/processJsonSubreddit.js index e6f644c..b73f94d 100644 --- a/inc/processJsonSubreddit.js +++ b/inc/processJsonSubreddit.js @@ -1,6 +1,6 @@ module.exports = function() { const config = require('../config'); - this.processJsonSubreddit = (json, from, subreddit_front, user_preferences) => { + this.processJsonSubreddit = (json, from, subreddit_front, user_preferences, saved) => { return new Promise(resolve => { (async () => { if(from === 'redis') { @@ -9,6 +9,17 @@ module.exports = function() { if(json.error) { resolve({ error: true, error_data: json }) } else { + if(saved) { + let t = { + data: { + before: null, + after: null, + children: json + } + } + json = t + } + let before = json.data.before let after = json.data.after diff --git a/routes.js b/routes.js index bc4b978..8f87f39 100644 --- a/routes.js +++ b/routes.js @@ -68,6 +68,181 @@ module.exports = (app, redis, fetch, RedditAPI) => { app.get('/privacy', (req, res, next) => { return res.render('privacypolicy', { user_preferences: req.cookies }) }) + + app.get('/gallery/:id', (req, res, next) => { + return res.redirect(`/comments/${req.params.id}`) + }) + + app.get('/saved', (req, res, next) => { + let saved = req.cookies.saved + + if(!saved || !Array.isArray(saved)) { + return res.render('saved', { + json: null, + user_preferences: req.cookies, + }) + } + + let key = `saved_posts:${saved.join(',')}` + redis.get(key, (error, json) => { + if(error) { + console.error(`Error getting saved_post ${saved_post} key from redis.`, error) + return res.redirect('/') + } + if(json) { + (async () => { + let processed_json = await processJsonSubreddit(json, 'redis', null, req.cookies, true) + if(!processed_json.error) { + return res.render('saved', { + json: processed_json, + user_preferences: req.cookies, + }) + } else { + return res.render('subreddit', { + json: null, + error: true, + data: processed_json, + user_preferences: req.cookies + }) + } + })() + } + }) + }) + + app.get('/save/:id', (req, res, next) => { + let post_id = req.params.id + let redis_key = req.query.rk + let back = req.query.b + let saved = req.cookies.saved + let fetched = req.query.f + + if(!post_id || !redis_key) + return res.redirect('/saved') + + if(!saved || !Array.isArray(saved)) + saved = [] + + if(saved.length > 100) + return res.send('You can not save more than 100 posts.') + + redis.get(redis_key, (error, json) => { + if(error) { + console.error(`Error getting the ${redis_key} key from redis (via /save/).`, error) + return res.redirect('/') + } + if(json) { + json = JSON.parse(json) + if(fetched === 'true' || redis_key.includes('/comments/')) + json = json[0] + + let post_to_save = false + for(var i = 0; i < json.data.children.length; i++) { + let post = json.data.children[i] + if(post.data.id === post_id) { + post_to_save = post + break + } + } + + if(post_to_save) { + if(!saved || !Array.isArray(saved)) + saved = [] + + for(var i = 0; i < saved.length; i++) { + if(post_to_save.data.id === saved[i]) + return res.redirect('/saved') + } + + let key = `saved_posts:${saved.join(',')}` + redis.get(key, (error, json) => { + if(error) { + console.error(`Error getting saved_posts ${key} key from redis.`, error) + return res.redirect('/') + } + links = JSON.parse(json) + if(!links) + links = [] + + links.unshift(post_to_save) + saved.unshift(post_to_save.data.id) + res.cookie('saved', saved, { maxAge: 3 * 365 * 24 * 60 * 60 * 1000, httpOnly: true }) + + let new_key = `saved_posts:${saved.join(',')}` + redis.set(new_key, JSON.stringify(links), (error) => { + if(error) + console.error(`Error saving ${new_key} to redis.`, error) + + if(!back) + return res.redirect('/saved') + else { + back = back.replace(/§2/g, '?').replace(/§1/g, '&') + return res.redirect(back) + } + }) + }) + } else { + return res.redirect(`/comments/${post_id}/?save=true&b=${back}`) + } + } else { + return res.redirect(`/comments/${post_id}/?save=true&b=${back}`) + } + }) + }) + + app.get('/unsave/:id', (req, res, next) => { + let post_id = req.params.id + let back = req.query.b + let saved = req.cookies.saved + + if(!post_id) + return res.redirect('/saved') + + if(!saved || !Array.isArray(saved)) + return res.redirect('/saved') + + let key = `saved_posts:${saved.join(',')}` + redis.get(key, (error, json) => { + if(error) { + console.error(`Error getting the ${key} key from redis (via /save/).`, error) + return res.redirect('/') + } + if(json) { + json = JSON.parse(json) + let post_found = false + for(var i = 0; i < json.length; i++) { + if(json[i].data.id === post_id) { + post_found = true + json.splice(i, 1) + for(var j = 0; j < saved.length; j++) { + if(saved[j] === post_id) + saved.splice(j, 1) + } + } + } + if(post_found) { + res.cookie('saved', saved, { maxAge: 3 * 365 * 24 * 60 * 60 * 1000, httpOnly: true }) + + let new_key = `saved_posts:${saved.join(',')}` + redis.set(new_key, JSON.stringify(json), (error) => { + if(error) + console.error(`Error saving ${new_key} to redis.`, error) + + if(!back) + return res.redirect('/saved') + else { + back = back.replace(/§2/g, '?').replace(/§1/g, '&') + return res.redirect(back) + } + }) + } else { + return res.redirect(`/saved`) + } + } else { + return res.redirect(`/saved`) + } + }) + }) app.get('/subreddits/:sort?', (req, res, next) => { let q = req.query.q @@ -394,7 +569,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { json: processed_json, sortby: sortby, past: past, - user_preferences: req.cookies + user_preferences: req.cookies, + redis_key: key }) } })() @@ -431,7 +607,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { json: processed_json, sortby: sortby, past: past, - user_preferences: req.cookies + user_preferences: req.cookies, + redis_key: key }) } })() @@ -458,6 +635,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { let post_id = req.params.post_id let comment = req.params.comment let comment_id = req.params.comment_id + let back = req.query.b + let save = req.query.save let post_url = false let comment_url = false @@ -479,10 +658,13 @@ module.exports = (app, redis, fetch, RedditAPI) => { if(json) { console.log('Got short URL for post key from redis.') json = JSON.parse(json) - if(post_url) + if(post_url) { + if(save === 'true') + return res.redirect(`/save/${post_id}/?rk=${key}&b=${back}&f=true`) return res.redirect(json[0].data.children[0].data.permalink) - else + } else { return res.redirect(json[1].data.children[0].data.permalink) + } } else { let url = '' if(config.use_reddit_oauth) { @@ -508,10 +690,13 @@ module.exports = (app, redis, fetch, RedditAPI) => { return res.render('index', { json: null, user_preferences: req.cookies }) } else { console.log('Fetched the short URL for post from Reddit.') - if(post_url) + if(post_url) { + if(save === 'true') + return res.redirect(`/save/${post_id}/?rk=${key}&b=${back}&f=true`) return res.redirect(json[0].data.children[0].data.permalink) - else + } else { return res.redirect(json[1].data.children[0].data.permalink) + } } }) }) @@ -820,7 +1005,10 @@ module.exports = (app, redis, fetch, RedditAPI) => { sortby: sortby, past: past, user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled + instance_nsfw_enabled: config.nsfw_enabled, + redis_key: key, + after: req.query.after, + before: req.query.before }) } else { return res.render('subreddit', { @@ -863,7 +1051,10 @@ module.exports = (app, redis, fetch, RedditAPI) => { sortby: sortby, past: past, user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled + instance_nsfw_enabled: config.nsfw_enabled, + redis_key: key, + after: req.query.after, + before: req.query.before }) } })() @@ -937,7 +1128,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { subreddit: subreddit, sortby: sortby, user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled + instance_nsfw_enabled: config.nsfw_enabled, + redis_key: comments_key }) } else { let key = `morechildren:${post_url};1` @@ -971,7 +1163,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { sortby: sortby, more_comments_page: 1, user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled + instance_nsfw_enabled: config.nsfw_enabled, + redis_key: comments_key }) })() }) @@ -1010,7 +1203,8 @@ module.exports = (app, redis, fetch, RedditAPI) => { subreddit: subreddit, sortby: sortby, user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled + instance_nsfw_enabled: config.nsfw_enabled, + redis_key: comments_key }) })() } diff --git a/static/css/styles.css b/static/css/styles.css index ca23764..c87b48f 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -444,6 +444,7 @@ footer a { padding: 0; color: #888; font-weight: bold; + margin: 0px 15px 0px 0px; } #links .link .entry .meta a:hover { text-decoration: underline; @@ -671,6 +672,12 @@ footer a { float: left; width: 100%; } +#post .info .links a { + font-size: var(--sm-font); +} +#post .info .links a { + float: initial; +} #post header { padding-top: 0; } @@ -709,6 +716,9 @@ footer a { font-size: small; color: #686868; } +#post .submitted a { + float: initial; +} #post .submitted a, #post .submitted span { margin-left: 5px; diff --git a/views/includes/topbar.pug b/views/includes/topbar.pug index 638c910..b507832 100644 --- a/views/includes/topbar.pug +++ b/views/includes/topbar.pug @@ -13,11 +13,13 @@ div#topbar 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 a(href="/r/popular") Popular a(href="/r/all") All + a(href="/saved") Saved a(href="/r/AskReddit") AskReddit a(href="/r/pics") pics a(href="/r/news") news diff --git a/views/index.pug b/views/index.pug index 0768728..dede57d 100644 --- a/views/index.pug +++ b/views/index.pug @@ -131,8 +131,22 @@ html span ▶ .preview img(src=""+ link.images.thumb +"", alt="") - a(href="" + link.permalink + "", class="comments") - | #{link.num_comments} comments + a(href="" + link.permalink + "", class="comments") #{link.num_comments} comments + - + let back_url = "/" + sortby + "§2t="+ (past ? past : '') +"" + if(before && !subreddit_front) + back_url = "/" + sortby + "§2t="+ (past ? past : '') +"§1before=" + before + "" + if(after) + back_url = "/" + sortby + "§2t=" + (past ? past : '') + "§1after=" + after + "" + - let saved_post = false + if user_preferences.saved + each post_id in user_preferences.saved + if post_id === link.id + - saved_post = true + if saved_post + 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 if json.info.before || json.info.after .view-more-links - var subreddit = 'all' diff --git a/views/post.pug b/views/post.pug index 83f723c..0d245f8 100644 --- a/views/post.pug +++ b/views/post.pug @@ -34,17 +34,28 @@ html h2 #{cleanTitle(post.title)} != post.link_flair span(class="domain") (#{post.domain}) - p.submitted - span(title="" + toUTCString(post.created) + "") submitted #{timeDifference(post.created)} by - if post.author === '[deleted]' - span [deleted] - else - a(href="/u/" + post.author + "") - | #{post.author} - != post.user_flair - .links - if post.over_18 - span.tag.nsfw NSFW + p.submitted + span(title="" + toUTCString(post.created) + "") submitted #{timeDifference(post.created)} by + if post.author === '[deleted]' + span [deleted] + else + a(href="/u/" + post.author + "") + | #{post.author} + != post.user_flair + .links + if post.over_18 + span.tag.nsfw NSFW + - + let back_url = "/r/" + subreddit + "/comments/" + post.id + let saved_post = false + if user_preferences.saved + each post_id in user_preferences.saved + if post_id === post.id + - saved_post = true + if saved_post + 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 if post.crosspost.is_crosspost === true .crosspost .title diff --git a/views/saved.pug b/views/saved.pug new file mode 100644 index 0000000..ac30e6c --- /dev/null +++ b/views/saved.pug @@ -0,0 +1,98 @@ +doctype html +html + head + title saved + include includes/head.pug + body(class=""+ user_preferences.theme +"") + include includes/topbar.pug + if json === null + h1 No saved posts + else + header + a(href="/", class="main") + h1 teddit + .bottom + a(href="/saved", class="subreddit") + h2 saved + #links.sr + if json.links.length === 0 + p No saved posts + else + each link in json.links + .link + .upvotes + .arrow + span #{kFormatter(link.ups)} + .arrow.down + .image + if link.images + if link.is_self_link + a(href="" + link.permalink + "") + img(src="" + link.images.thumb + "", alt="") + else + a(href=""+ link.url +"", rel="noopener noreferrer") + img(src="" + link.images.thumb + "", alt="") + else + a(href="" + link.permalink + "") + .no-image no image + .entry + .title + if link.is_self_link + a(href="" + link.permalink + "") + h2(class="" + (link.stickied ? 'green' : '') + "") #{cleanTitle(link.title)} + != link.link_flair + span (#{link.domain}) + else + a(href="" + link.url + "", rel="noopener noreferrer") + h2(class="" + (link.stickied ? 'green' : '') + "") #{cleanTitle(link.title)} + != link.link_flair + span (#{link.domain}) + .meta + p.submitted submitted + span(title="" + toUTCString(link.created) + "") #{timeDifference(link.created)} by + if link.author === '[deleted]' + span(class="deleted") [deleted] + else + a(href="/u/" + link.author + "") + | #{link.author} + != link.user_flair + p.to to + a(href="/r/" + link.subreddit + "") + | #{link.subreddit} + if link.stickied + span(class="green") stickied + .links + if link.over_18 + span.tag.nsfw NSFW + if link.selftext_html + details + summary + .line + .line + .line + .selftext + != unescape(link.selftext_html) + if (link.images && link.images.preview) + style. + details.preview-container img { + width: 100% !important; + height: auto !important; + max-width: none !important; + max-height: none !important; + opacity: 0; + } + details.preview-container[open][data-url="#{link.images.preview}"] .preview { + width: 100%; + height: auto; + background-image: url('#{link.images.preview}'); + background-repeat: no-repeat; + background-size: contain; + } + details.preview-container(data-url="" + link.images.preview + "") + summary + span ▶ + .preview + img(src=""+ link.images.thumb +"", alt="") + a(href="" + link.permalink + "", class="comments") #{link.num_comments} comments + a(href="/unsave/" + link.id + "") unsave + include includes/footer.pug diff --git a/views/subreddit.pug b/views/subreddit.pug index 683b003..1acba65 100644 --- a/views/subreddit.pug +++ b/views/subreddit.pug @@ -157,8 +157,22 @@ html span ▶ .preview img(src=""+ link.images.thumb +"", alt="") - a(href="" + link.permalink + "", class="comments") - | #{link.num_comments} comments + a(href="" + link.permalink + "", class="comments") #{link.num_comments} comments + - + let back_url = "/r/" + subreddit + "/" + sortby + "§2t="+ (past ? past : '') +"" + if(before && !subreddit_front) + back_url = "/r/" + subreddit + "/" + sortby + "§2t="+ (past ? past : '') +"§1before=" + before + "" + if(after) + back_url = "/r/" + subreddit + "/" + sortby + "§2t=" + (past ? past : '') + "§1after=" + after + "" + - let saved_post = false + if user_preferences.saved + each post_id in user_preferences.saved + if post_id === link.id + - saved_post = true + if saved_post + 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 if json.info.before || json.info.after .view-more-links if json.info.before && !subreddit_front