fix load more comments (morechildren-endpoint), fixes #122

This commit is contained in:
teddit 2021-04-10 15:42:01 +02:00
parent 006ac93de5
commit 567e6f7797
5 changed files with 171 additions and 157 deletions

View File

@ -1,5 +1,5 @@
module.exports = function() { 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) => { return new Promise((resolve, reject) => {
(async () => { (async () => {
let comments_html let comments_html
@ -68,31 +68,49 @@ module.exports = function() {
if(comments.children.length > 0) { if(comments.children.length > 0) {
let parent_id = comments.parent_id.split('_')[1] let parent_id = comments.parent_id.split('_')[1]
if(post_id === parent_id && !morechildren_ids) { 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 = ` comments_html = `
<form method="POST"> <form method="POST">
<button type="submit">load more comments (${comments.count})</button> <button type="submit">load more comments (${comments.count})</button>
<input type="hidden" name="url" id="url" value="${post_url}"> <input type="hidden" name="comment_ids" id="comment_ids" value="${more_comments.join()}">
<input type="hidden" name="all_ids" id="all_ids" value="${comments.children.join()}">
</form> </form>
` `
} else { } else {
if(!morechildren_ids) {
let load_comms_href = parent_id let load_comms_href = parent_id
if(!morechildren_ids) {
comments_html = ` comments_html = `
<div class="load-more-comments"> <div class="load-more-comments">
<a href="${load_comms_href}#c">load more comments (${comments.count})</a> <a href="${load_comms_href}#c">load more comments (${comments.count})</a>
</div> </div>
` `
} else { } else {
morechildren_ids = JSON.parse(morechildren_ids) 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 = ` comments_html = `
<form method="POST"> <form method="POST">
<button type="submit">load more comments (${morechildren_ids.length})</button> <button type="submit">load more comments (${more_comments.length})</button>
<input type="hidden" name="url" id="url" value="${post_url}"> <input type="hidden" name="comment_ids" id="comment_ids" value="${more_comments.join()}">
<input type="hidden" name="all_ids" id="all_ids" value='${morechildren_ids.join()}'>
</form> </form>
` `
} else {
comments_html = `
<div class="load-more-comments">
<a href="${load_comms_href}#c">load more comments (${comments.count})</a>
</div>
`
}
} }
} }
} else { } else {
@ -106,6 +124,20 @@ 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 += `</details></div>`
}
}
}
}
if(comments.replies) { if(comments.replies) {
for(var i = 0; i < comments.replies.length; i++) { for(var i = 0; i < comments.replies.length; i++) {
let comment = comments.replies[i] let comment = comments.replies[i]
@ -163,7 +195,7 @@ module.exports = function() {
if(comment.replies) { if(comment.replies) {
if(comment.replies.length) { if(comment.replies.length) {
for(var j = 0; j < comment.replies.length; j++) { for(var j = 0; j < comment.replies.length; j++) {
let next_reply let next_reply = false
if(comment.replies[j+1]) { if(comment.replies[j+1]) {
next_reply = comment.replies[j+1] next_reply = comment.replies[j+1]
} }

View File

@ -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) { if(post.crosspost_parent_list) {
post.crosspost = post.crosspost_parent_list[0] post.crosspost = post.crosspost_parent_list[0]
} }
if(post.crosspost) { 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 = { obj.crosspost = {
author: post.crosspost.author, author: post.crosspost.author,
created: post.crosspost.created_utc, created: post.crosspost.created_utc,
@ -164,7 +164,7 @@ module.exports = function(fetch) {
score_hidden: comment.score_hidden, score_hidden: comment.score_hidden,
edited: comment.edited, edited: comment.edited,
replies: [], replies: [],
depth: 0, depth: comment.depth,
user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(comment) : ''), user_flair: (user_preferences.flairs != 'false' ? await formatUserFlair(comment) : ''),
controversiality: (user_preferences.highlight_controversial != 'false' ? comment.controversiality : '') 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) => { this.finalizeJsonPost = async (processed_json, post_id, post_url, morechildren_ids, viewing_comment, user_preferences) => {
let comments_html = `<div class="comments">` let comments_html = `<div class="comments">`
let comments = processed_json.comments let comments = processed_json.comments
let last_known_depth = undefined
for(var i = 0; i < comments.length; i++) { for(var i = 0; i < comments.length; i++) {
let next_comment let next_comment = false
if(comments[i+1]) { if(comments[i+1]) {
next_comment = 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 += `</div>` comments_html += `</div>`

View File

@ -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

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "teddit", "name": "teddit",
"version": "0.1.1", "version": "0.3.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

169
routes.js
View File

@ -11,6 +11,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
let tedditApiSubreddit = require('./inc/teddit_api/handleSubreddit.js')(); let tedditApiSubreddit = require('./inc/teddit_api/handleSubreddit.js')();
let tedditApiUser = require('./inc/teddit_api/handleUser.js')(); let tedditApiUser = require('./inc/teddit_api/handleUser.js')();
let processSubredditsExplore = require('./inc/processSubredditsExplore.js')(); let processSubredditsExplore = require('./inc/processSubredditsExplore.js')();
let processMoreComments = require('./inc/processMoreComments.js')();
app.all('*', (req, res, next) => { app.all('*', (req, res, next) => {
let themeOverride = req.query.theme let themeOverride = req.query.theme
@ -1208,7 +1209,7 @@ module.exports = (app, redis, fetch, RedditAPI) => {
let sortby = req.query.sort let sortby = req.query.sort
let comment_id = '' let comment_id = ''
let viewing_comment = false let viewing_comment = false
let more_comments_cursor = req.query.cursor let comment_ids = req.query.comment_ids
let context = parseInt(req.query.context) let context = parseInt(req.query.context)
if(req.params.comment_id) { if(req.params.comment_id) {
@ -1237,9 +1238,23 @@ module.exports = (app, redis, fetch, RedditAPI) => {
if(json) { if(json) {
console.log(`Got ${comments_url} key from redis.`); console.log(`Got ${comments_url} key from redis.`);
(async () => { (async () => {
if(!more_comments_cursor) { let parsed = false
let processed_json = await processJsonPost(json, false, req.cookies) let more_comments = null
let finalized_json = await finalizeJsonPost(processed_json, id, post_url, null, viewing_comment, req.cookies) 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', { return res.render('post', {
post: finalized_json.post_data, post: finalized_json.post_data,
comments: finalized_json.comments, comments: finalized_json.comments,
@ -1252,49 +1267,6 @@ module.exports = (app, redis, fetch, RedditAPI) => {
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
}) })
} 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
})
})()
})
}
})
}
})
}
})() })()
} else { } else {
let url = '' let url = ''
@ -1315,8 +1287,20 @@ module.exports = (app, redis, fetch, RedditAPI) => {
} else { } else {
console.log(`Fetched the JSON from reddit.com${comments_url}.`); console.log(`Fetched the JSON from reddit.com${comments_url}.`);
(async () => { (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 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', { return res.render('post', {
post: finalized_json.post_data, post: finalized_json.post_data,
comments: finalized_json.comments, comments: finalized_json.comments,
@ -1801,82 +1785,21 @@ module.exports = (app, redis, fetch, RedditAPI) => {
}) })
app.post('/r/:subreddit/comments/:id/:snippet', (req, res, next) => { app.post('/r/:subreddit/comments/:id/:snippet', (req, res, next) => {
/* morechildren route */ /**
let all_ids = req.body.all_ids * This is the "morechildren" route. This route is called when the
let post_url = req.body.url * "load more comments" button at the bottom of some post is clicked.
*/
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) 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.`) 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.`)
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()) let subreddit = req.params.subreddit
.then(result => { let id = req.params.id
if(result.status === 200) { let snippet = encodeURIComponent(req.params.snippet)
result.json() let post_url = `/r/${subreddit}/comments/${id}/${snippet}/`
.then(json => { let page = req.query.page
if(json.json.data) { let comment_ids = req.body.comment_ids
if(json.json.data.things) {
let comments = json.json.data.things return res.redirect(`${post_url}?comment_ids=${comment_ids}&page=1`)
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
})
})
}
})
}
}) })
function resetPreferences(res) { function resetPreferences(res) {