From fd3c426770bc993f5a3e52aa1f7ca55bded1177d Mon Sep 17 00:00:00 2001 From: Lukas Aldersley Date: Thu, 5 Jun 2025 19:15:30 +0200 Subject: [PATCH 1/4] Implement loading comments beyond depth limit As reddit will only return up to 10 nested levels of comments in their json API, any comment beyond that must be loaded in a seperate call --- index.html | 8 +++++++ script.js | 68 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index 15a290c..94d979d 100644 --- a/index.html +++ b/index.html @@ -28,6 +28,14 @@

Export reddit post to markdown format

/> + +
+ + +
+
diff --git a/script.js b/script.js index 1f51181..fbba087 100644 --- a/script.js +++ b/script.js @@ -4,6 +4,7 @@ let output = ''; let style = 0; let escapeNewLine = false; let spaceComment = false; +var postLoadAdditionalComments = false var selectedProxy = 'auto'; // CORS Proxy configurations @@ -36,7 +37,7 @@ const onDocumentReady = () => { }; const getQueryParamUrl = () => new URLSearchParams(window.location.search).get( - 'url') ?? null; + 'url') ?? null; const getFieldUrl = () => document.getElementById('url-field').value; function formatRedditJsonUrl(url) { @@ -188,7 +189,7 @@ async function fetchData(url) { const comments = data[1].data.children; displayTitle(post); output += '\n\n## Comments\n\n'; - comments.forEach(displayComment); + comments.forEach((comment) => displayComment(comment, null)); console.log('Done'); let output_display = document.getElementById('output-display'); @@ -216,6 +217,20 @@ async function fetchData(url) { } } +function loadMoreComments(url, parentid, depthInd) { + const h2 = new XMLHttpRequest() + //to allow the newly loaded comments to appear in the correct place, this call has to be synchronous + h2.open('GET', `${url}/${parentid}.json`, false); + //setting a desired response type is not supported for non-async calls + //h2.responseType = 'json'; + h2.send(); + + //as a response type cannot be set, the result needs to be parsed to JSON manually. + const d2 = JSON.parse(h2.responseText) + const comments = d2[1].data.children[0].data.replies.data.children; + comments.forEach((comment) => displayComment(comment, depthInd)); +} + function setStyle() { if (document.getElementById('treeOption').checked) { style = 0; @@ -235,6 +250,12 @@ function setStyle() { spaceComment = false; } + if (document.getElementById('postLoadComments').checked) { + postLoadAdditionalComments = true; + } else { + postLoadAdditionalComments = false; + } + selectedProxy = document.getElementById('proxySelection').value; } @@ -266,7 +287,7 @@ function download(text, name, type) { document.getElementById('copyButton').removeAttribute('disabled'); let download_button = document.getElementById('downloadButton'); download_button.removeAttribute('disabled'); - let file = new Blob([text], {type: type}); + let file = new Blob([text], { type: type }); download_button.href = URL.createObjectURL(file); download_button.download = name; } @@ -288,39 +309,46 @@ function formatComment(text) { } } -function displayComment(comment, index) { +function displayComment(comment, preexistingDepth = null) { + let currentDepth = preexistingDepth != null ? preexistingDepth : comment.data.depth; + let depthTag if (style == 0) { - depthTag = '─'.repeat(comment.data.depth); - if (depthTag != '') { - output += `├${depthTag} `; + if (currentDepth > 0) { + depthTag = `├${'─'.repeat(currentDepth)} `; } else { - output += `##### `; + depthTag = `##### `; } } else { - depthTag = '\t'.repeat(comment.data.depth); - if (depthTag != '') { - output += `${depthTag}- `; + if (currentDepth > 0) { + depthTag = `${'\t'.repeat(currentDepth)}- `; } else { - output += `- `; + depthTag = `- `; } } if (comment.data.body) { console.log(formatComment(comment.data.body)); - output += `${formatComment( - comment.data.body)} ⏤ by *${comment.data.author}* (↑ ${ - comment.data.ups - }/ ↓ ${comment.data.downs})\n`; + output += `${depthTag}${formatComment( + comment.data.body)} ⏤ by *${comment.data.author}* (↑ ${comment.data.ups + }/ ↓ ${comment.data.downs})\n`; + } else if (comment.kind === "more") { + let parentID = comment.data.parent_id.substring(3); + if (postLoadAdditionalComments) { + loadMoreComments(getFieldUrl(), parentID, currentDepth); "" + } + else { + output += `${depthTag}comment depth-limit (${currentDepth}) reached\n`; + } } else { - output += 'deleted \n'; + output += `${depthTag}deleted\n`; } if (comment.data.replies) { - const subComment = comment.data.replies.data.children; - subComment.forEach(displayComment); + const subComments = comment.data.replies.data.children; + subComments.forEach((subComment) => displayComment(subComment, preexistingDepth != null ? preexistingDepth + 1 : null)); } - if (comment.data.depth == 0 && comment.data.replies) { + if (currentDepth == 0 && comment.data.replies) { if (style == 0) { output += '└────\n\n'; } From e6be5474cd08d75df6ff102c667b38e2800214a1 Mon Sep 17 00:00:00 2001 From: Lukas Aldersley Date: Fri, 6 Jun 2025 20:39:16 +0200 Subject: [PATCH 2/4] add link to reddit if depth exceeded --- script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script.js b/script.js index fbba087..21c29fc 100644 --- a/script.js +++ b/script.js @@ -337,7 +337,7 @@ function displayComment(comment, preexistingDepth = null) { loadMoreComments(getFieldUrl(), parentID, currentDepth); "" } else { - output += `${depthTag}comment depth-limit (${currentDepth}) reached\n`; + output += `${depthTag}comment depth-limit (${currentDepth}) reached. [view on reddit](${getFieldUrl()}/${parentID})\n`; } } else { output += `${depthTag}deleted\n`; From 40366063834795c721880dbb5d98a94450254b0d Mon Sep 17 00:00:00 2001 From: Lukas Aldersley Date: Fri, 6 Jun 2025 23:03:35 +0200 Subject: [PATCH 3/4] added output option for comments in nested blockquotes --- index.html | 2 ++ script.js | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 94d979d..88fdc09 100644 --- a/index.html +++ b/index.html @@ -42,6 +42,8 @@

Export reddit post to markdown format

+ +
diff --git a/script.js b/script.js index 21c29fc..f50007f 100644 --- a/script.js +++ b/script.js @@ -4,7 +4,7 @@ let output = ''; let style = 0; let escapeNewLine = false; let spaceComment = false; -var postLoadAdditionalComments = false +let postLoadAdditionalComments = false var selectedProxy = 'auto'; // CORS Proxy configurations @@ -234,8 +234,10 @@ function loadMoreComments(url, parentid, depthInd) { function setStyle() { if (document.getElementById('treeOption').checked) { style = 0; - } else { + } else if (document.getElementById('listOption').checked) { style = 1; + } else { + style = 2 } if (document.getElementById('escapeNewLine').checked) { @@ -318,35 +320,57 @@ function displayComment(comment, preexistingDepth = null) { } else { depthTag = `##### `; } - } else { + } else if (style == 1) { if (currentDepth > 0) { depthTag = `${'\t'.repeat(currentDepth)}- `; } else { depthTag = `- `; } } + else { + depthTag = '>'.repeat(currentDepth + 1); + } if (comment.data.body) { console.log(formatComment(comment.data.body)); - output += `${depthTag}${formatComment( - comment.data.body)} ⏤ by *${comment.data.author}* (↑ ${comment.data.ups - }/ ↓ ${comment.data.downs})\n`; + if (style < 2) { + output += `${depthTag}${formatComment( + comment.data.body)} ⏤ by *${comment.data.author}* (↑ ${comment.data.ups + }/ ↓ ${comment.data.downs})\n`; + } + else { + if (currentDepth == 0) { + /*to make it unambiguous if two block quotes should be seperate or one and the same + they need to be seperated by at least one character not part of either (I chose NBSP)*/ + output += '&nbsp;\n\n' + } + output += `${depthTag}\n${depthTag}#### [**${comment.data.author}** ${comment.data.author_flair_text ? `'***${comment.data.author_flair_text}***' ` : ''}(↑ ${comment.data.ups}/ ↓ ${comment.data.downs}) @${new Date(comment.data.created_utc * 1000).toISOString()}${comment.data.edited ? ` (edited @${new Date(comment.data.edited * 1000).toISOString()})` : ''}](${getFieldUrl()}/${comment.data.id})\n${depthTag}\n${depthTag}${formatComment(comment.data.body).trimEnd().replace(/\n/g, `\n${depthTag}`)}\n` + } } else if (comment.kind === "more") { let parentID = comment.data.parent_id.substring(3); if (postLoadAdditionalComments) { loadMoreComments(getFieldUrl(), parentID, currentDepth); "" } else { - output += `${depthTag}comment depth-limit (${currentDepth}) reached. [view on reddit](${getFieldUrl()}/${parentID})\n`; + output += `${depthTag}${style == 2 ? `\n${depthTag}#### ` : ''}comment depth-limit (${currentDepth}) reached. [view on reddit](${getFieldUrl()}/${parentID})\n`; } } else { - output += `${depthTag}deleted\n`; + output += `${depthTag}${style == 2 ? `\n${depthTag}#### ` : ''}deleted\n`; } if (comment.data.replies) { const subComments = comment.data.replies.data.children; subComments.forEach((subComment) => displayComment(subComment, preexistingDepth != null ? preexistingDepth + 1 : null)); } + if (style == 2) { + /*do note, this is NOT depthTag, it has one fewer symbol + this is required forcibly split the block-quotes for two comments on the same level. + It technically generates more markers than strictly necessary, + but those extra ones are not harmful, and depending on your interpretation, + can even more sematically correct than if they were absent*/ + output += '>'.repeat(currentDepth); + output += '\n' + } if (currentDepth == 0 && comment.data.replies) { if (style == 0) { From f035f0b46aaaa62cb7b56694e8834895c2ee8ad1 Mon Sep 17 00:00:00 2001 From: Lukas Aldersley Date: Sat, 7 Jun 2025 00:48:30 +0200 Subject: [PATCH 4/4] minor fix for spiler tags in blockquote comments --- script.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script.js b/script.js index f50007f..32238f9 100644 --- a/script.js +++ b/script.js @@ -344,7 +344,8 @@ function displayComment(comment, preexistingDepth = null) { they need to be seperated by at least one character not part of either (I chose NBSP)*/ output += '&nbsp;\n\n' } - output += `${depthTag}\n${depthTag}#### [**${comment.data.author}** ${comment.data.author_flair_text ? `'***${comment.data.author_flair_text}***' ` : ''}(↑ ${comment.data.ups}/ ↓ ${comment.data.downs}) @${new Date(comment.data.created_utc * 1000).toISOString()}${comment.data.edited ? ` (edited @${new Date(comment.data.edited * 1000).toISOString()})` : ''}](${getFieldUrl()}/${comment.data.id})\n${depthTag}\n${depthTag}${formatComment(comment.data.body).trimEnd().replace(/\n/g, `\n${depthTag}`)}\n` + output += `${depthTag}\n${depthTag}#### [**${comment.data.author}** ${comment.data.author_flair_text ? `'***${comment.data.author_flair_text}***' ` : ''}(↑ ${comment.data.ups}/ ↓ ${comment.data.downs}) @${new Date(comment.data.created_utc * 1000).toISOString()}${comment.data.edited ? ` (edited @${new Date(comment.data.edited * 1000).toISOString()})` : ''}](${getFieldUrl()}/${comment.data.id})\n${depthTag}\n${depthTag}${formatComment(comment.data.body).trimEnd().replace(/!</g, '!&lt;').replace(/>!/g, '&gt;!').replace(/\n/g, `\n${depthTag}`)}\n`; + //the !</>! replacement is to force retain the escaping of in spoiler tags to avoid confusion between blockquotes and spoilers } } else if (comment.kind === "more") { let parentID = comment.data.parent_id.substring(3);