diff --git a/inc/compilePostComments.js b/inc/compilePostComments.js index 2f21e79..1560aa8 100644 --- a/inc/compilePostComments.js +++ b/inc/compilePostComments.js @@ -1,5 +1,5 @@ module.exports = function() { - this.compilePostCommentsHtml = (comments, next_comment, post_id, post_url, morechildren_ids, post_author, viewing_comment, user_preferences) => { + this.compilePostCommentsHtml = (comments, next_comment, post_id, post_url, morechildren_ids, post_author, viewing_comment, user_preferences, last_known_depth) => { return new Promise((resolve, reject) => { (async () => { let comments_html @@ -13,7 +13,7 @@ module.exports = function() { if(!user_preferences) user_preferences = {} - + if(comments.author !== undefined && comments.body_html !== undefined) { let classlist = [] let submitter_link = '' @@ -68,31 +68,49 @@ module.exports = function() { if(comments.children.length > 0) { let parent_id = comments.parent_id.split('_')[1] if(post_id === parent_id && !morechildren_ids) { + let more_comments = [] + if(comments.children.length > 100) { + more_comments = comments.children.slice(0, 100) + } else { + more_comments = comments.children + } + comments_html = `
- - +
` } else { + let load_comms_href = parent_id if(!morechildren_ids) { - let load_comms_href = parent_id - comments_html = `
load more comments (${comments.count})
` } else { - morechildren_ids = JSON.parse(morechildren_ids) - comments_html = ` -
- - - -
- ` + if(next_comment === false) { + let more_comments = morechildren_ids[morechildren_ids.length - 1].data.children + if(more_comments.length > 100) { + more_comments = more_comments.slice(0, 100) + } else { + more_comments = more_comments + } + comments_html = ` +
+ + +
+ ` + } else { + comments_html = ` +
+ load more comments (${comments.count}) +
+ ` + } + } } } else { @@ -105,7 +123,21 @@ module.exports = function() { } } } - + + if(morechildren_ids) { + if(next_comment.depth != undefined) { + if(next_comment.depth < last_known_depth) { + let times = last_known_depth - next_comment.depth + if(next_comment.depth == 0) { + times = last_known_depth + } + for(var i = 0; i < times; i++) { + comments_html += `` + } + } + } + } + if(comments.replies) { for(var i = 0; i < comments.replies.length; i++) { let comment = comments.replies[i] @@ -163,7 +195,7 @@ module.exports = function() { if(comment.replies) { if(comment.replies.length) { for(var j = 0; j < comment.replies.length; j++) { - let next_reply + let next_reply = false if(comment.replies[j+1]) { next_reply = comment.replies[j+1] } @@ -200,7 +232,7 @@ module.exports = function() { next_comment_parent_id = next_comment.parent_id.split('_')[1] } } - + if((comments.replies || comments.author !== undefined) && next_comment_parent_id !== comments.id) { comments_html += `` } diff --git a/inc/processJsonPost.js b/inc/processJsonPost.js index e621c0c..ef16664 100644 --- a/inc/processJsonPost.js +++ b/inc/processJsonPost.js @@ -76,13 +76,13 @@ module.exports = function(fetch) { } } - obj = await processPostMedia(obj, post, post.media, has_gif, reddit_video, gif_to_mp4, user_preferences) + 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) { - obj = await processPostMedia(obj, post.crosspost, post.crosspost.media, has_gif, reddit_video, gif_to_mp4, user_preferences) + 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, @@ -164,7 +164,7 @@ module.exports = function(fetch) { score_hidden: comment.score_hidden, edited: comment.edited, replies: [], - depth: 0, + depth: comment.depth, user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(comment) : ''), controversiality: (user_preferences.highlight_controversial != 'false' ? comment.controversiality : '') } @@ -206,12 +206,17 @@ module.exports = function(fetch) { this.finalizeJsonPost = async (processed_json, post_id, post_url, morechildren_ids, viewing_comment, user_preferences) => { let comments_html = `
` let comments = processed_json.comments + let last_known_depth = undefined for(var i = 0; i < comments.length; i++) { - let next_comment + let next_comment = false if(comments[i+1]) { next_comment = comments[i+1] } - comments_html += await compilePostCommentsHtml(comments[i], next_comment, post_id, post_url, morechildren_ids, processed_json.author, viewing_comment, user_preferences) + 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 += `
` diff --git a/inc/processMoreComments.js b/inc/processMoreComments.js new file mode 100644 index 0000000..4056d8e --- /dev/null +++ b/inc/processMoreComments.js @@ -0,0 +1,54 @@ +module.exports = function() { + const config = require('../config') + this.moreComments = (fetch, redis, post_url, comment_ids, id) => { + return new Promise(resolve => { + (async () => { + 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) + } + 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) + } + }) + } else { + resolve(false) + } + } else { + resolve(false) + } + }) + } else { + console.error(`Something went wrong while fetching data from Reddit. ${result.status} – ${result.statusText} (moreComments())`) + resolve(false) + } + }).catch(error => { + console.log(`Error fetching the JSON from Reddit (endpoint "morechildren") with url: ${url}. (moreComments())`, error) + resolve(false) + }) + } + }) + })() + }) + } +}1 diff --git a/package-lock.json b/package-lock.json index daa7cf8..a1cf006 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "teddit", - "version": "0.1.1", + "version": "0.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/routes.js b/routes.js index fa5ccec..2f7c96b 100644 --- a/routes.js +++ b/routes.js @@ -11,6 +11,7 @@ module.exports = (app, redis, fetch, RedditAPI) => { let tedditApiSubreddit = require('./inc/teddit_api/handleSubreddit.js')(); let tedditApiUser = require('./inc/teddit_api/handleUser.js')(); let processSubredditsExplore = require('./inc/processSubredditsExplore.js')(); + let processMoreComments = require('./inc/processMoreComments.js')(); app.all('*', (req, res, next) => { let themeOverride = req.query.theme @@ -1208,7 +1209,7 @@ module.exports = (app, redis, fetch, RedditAPI) => { let sortby = req.query.sort let comment_id = '' let viewing_comment = false - let more_comments_cursor = req.query.cursor + let comment_ids = req.query.comment_ids let context = parseInt(req.query.context) if(req.params.comment_id) { @@ -1237,64 +1238,35 @@ module.exports = (app, redis, fetch, RedditAPI) => { if(json) { console.log(`Got ${comments_url} key from redis.`); (async () => { - if(!more_comments_cursor) { - let processed_json = await processJsonPost(json, false, req.cookies) - let finalized_json = await finalizeJsonPost(processed_json, id, post_url, null, viewing_comment, req.cookies) - return res.render('post', { - post: finalized_json.post_data, - comments: finalized_json.comments, - viewing_comment: viewing_comment, - post_url: post_url, - subreddit: subreddit, - sortby: sortby, - user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled, - post_media_max_heights: config.post_media_max_heights, - redis_key: comments_key - }) - } else { - let key = `morechildren:${post_url};1` - redis.get(key, (error, json) => { - if(error) { - console.error(`Error getting the ${key} key from redis.`, error) - return res.render('index', { json: null, user_preferences: req.cookies }) - } - if(json) { - console.log(`Got ${key} key from redis.`); - redis.get(post_url, (error, post_json) => { - if(error) { - console.error(`Error getting the ${post_url} key from redis.`, error) - return res.render('index', { json: null, user_preferences: req.cookies }) - } - if(post_json) { - redis.get(`morechildren_ids:${post_url}`, (error, morechildren_ids) => { - (async () => { - post_json = JSON.parse(post_json) - json = JSON.parse(json) - post_json[1].data.children = json - let processed_json = await processJsonPost(post_json, true, req.cookies) - let finalized_json = await finalizeJsonPost(processed_json, id, post_url, morechildren_ids) - - return res.render('post', { - post: finalized_json.post_data, - comments: finalized_json.comments, - viewing_comment: false, - post_url: post_url, - subreddit: req.params.subreddit, - sortby: sortby, - more_comments_page: 1, - user_preferences: req.cookies, - instance_nsfw_enabled: config.nsfw_enabled, - post_media_max_heights: config.post_media_max_heights, - redis_key: comments_key - }) - })() - }) - } - }) - } - }) + let parsed = false + let more_comments = null + if(comment_ids) { + let key = `${post_url}:morechildren:comment_ids:${comment_ids}` + more_comments = await moreComments(fetch, redis, post_url, comment_ids, id) + + if(more_comments === false) { + return res.redirect(post_url) + } else { + json = JSON.parse(json) + json[1].data.children = more_comments + parsed = true + } } + + let processed_json = await processJsonPost(json, parsed, req.cookies) + let finalized_json = await finalizeJsonPost(processed_json, id, post_url, more_comments, viewing_comment, req.cookies) + return res.render('post', { + post: finalized_json.post_data, + comments: finalized_json.comments, + viewing_comment: viewing_comment, + post_url: post_url, + subreddit: subreddit, + sortby: sortby, + user_preferences: req.cookies, + instance_nsfw_enabled: config.nsfw_enabled, + post_media_max_heights: config.post_media_max_heights, + redis_key: comments_key + }) })() } else { let url = '' @@ -1315,8 +1287,20 @@ module.exports = (app, redis, fetch, RedditAPI) => { } else { console.log(`Fetched the JSON from reddit.com${comments_url}.`); (async () => { + let more_comments = null + if(comment_ids) { + let key = `${post_url}:morechildren:comment_ids:${comment_ids}` + more_comments = await moreComments(fetch, redis, post_url, comment_ids, id) + + if(more_comments === false) { + return res.redirect(post_url) + } else { + json[1].data.children = more_comments + } + } + let processed_json = await processJsonPost(json, true, req.cookies) - let finalized_json = await finalizeJsonPost(processed_json, id, post_url, null, viewing_comment) + let finalized_json = await finalizeJsonPost(processed_json, id, post_url, more_comments, viewing_comment) return res.render('post', { post: finalized_json.post_data, comments: finalized_json.comments, @@ -1801,82 +1785,21 @@ module.exports = (app, redis, fetch, RedditAPI) => { }) app.post('/r/:subreddit/comments/:id/:snippet', (req, res, next) => { - /* morechildren route */ - let all_ids = req.body.all_ids - let post_url = req.body.url + /** + * This is the "morechildren" route. This route is called when the + * "load more comments" button at the bottom of some post is clicked. + */ + if(!config.use_reddit_oauth) + return res.send(`This instance is using Reddit's public API (non-OAuth), and therefore this endpoint is not supported. In other words, this feature is only available if the instance is using Reddit OAuth API.`) - if(!all_ids || !post_url || !post_url.startsWith('/r/')) { - return res.render('index', { json: null, user_preferences: req.cookies }) - } else { - let post_id = post_url.split('/')[4] - let ids_to_show = '' - all_ids = all_ids.split(',') - // TODO: paging - let page = 1 - if(all_ids.length > 100) { - ids_to_show = all_ids.slice(0,100) - ids_to_show = ids_to_show.join() - } - - let key = `morechildren:${post_url};1` - redis.get(key, (error, json) => { - if(error) { - console.error(`Error getting the ${key} key from redis.`, error) - return res.render('index', { json: null, user_preferences: req.cookies }) - } - if(json) { - console.log(`Redirecting to ${post_url} with cursor...`); - return res.redirect(`${post_url}?cursor=${page}&page=${page}`) - } else { - if(!config.use_reddit_oauth) - return res.send(`This instance is using Reddit's public API (non-OAuth), and therefore this endpoint is not supported.`) - let url = `https://oauth.reddit.com/api/morechildren?api_type=json&children=${ids_to_show}&limit_children=false&link_id=t3_${post_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.`, error) - return res.render('post', { post: null, user_preferences: req.cookies }) - } else { - redis.setex(`morechildren_ids:${post_url}`, config.setexs.posts, JSON.stringify(all_ids)) - console.log(`Fetched the JSON from Reddit (endpoint "morechildren") with url: ${url}.`) - console.log(`Redirecting to ${post_url} with cursor...`) - return res.redirect(`${post_url}?cursor=${page}&page=${page}`) - } - }) - } else { - return res.redirect(post_url) - } - } else { - return res.redirect(post_url) - } - }) - } 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.log(`Error fetching the JSON from Reddit (endpoint "morechildren") with url: ${url}.`, error) - return res.render('index', { - json: null, - http_status_code: result.status, - user_preferences: req.cookies - }) - }) - } - }) - } + let subreddit = req.params.subreddit + let id = req.params.id + let snippet = encodeURIComponent(req.params.snippet) + let post_url = `/r/${subreddit}/comments/${id}/${snippet}/` + let page = req.query.page + let comment_ids = req.body.comment_ids + + return res.redirect(`${post_url}?comment_ids=${comment_ids}&page=1`) }) function resetPreferences(res) {