Created
February 12, 2024 14:40
-
-
Save zudsniper/98af9b1a025e5e1639e9566e19871acf to your computer and use it in GitHub Desktop.
🛩️ portable script to instantly download chatgpt conversation as markdown by pasting script into chromium devtools. AUTHOR @Creative_Original918 on Reddit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ALL CREDIT TO @Creative_Original918 on reddit for this! | |
* https://old.reddit.com/r/ChatGPT/comments/zm237o/save_your_chatgpt_conversation_as_a_markdown_file/jdjwyyo/ | |
*/ | |
function SaveChatGPTtoMD() { | |
const chatMessages = document.querySelectorAll(".text-base"); | |
const pageTitle = document.title; const now = new Date(); const dateString = `${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')}-${now.getHours().toString().padStart(2, '0')}-${now.getMinutes().toString().padStart(2, '0')}-${now.getSeconds().toString().padStart(2, '0')}`; | |
let fileName = "ChatGPT log - " + pageTitle + ' - ' + dateString + ".md"; | |
let markdownContent = ""; | |
for (const message of chatMessages) { | |
let Revision = ''; const revisionElement = message.querySelector(".text-xs .flex-grow"); // Revision Count: .text-xs means it has revision and .flex-grow is where the text is stored | |
if (revisionElement && revisionElement.innerHTML) { Revision = `Edit Revision: **${revisionElement.innerHTML}**\n`; } | |
if (message.querySelector(".whitespace-pre-wrap")) { | |
let messageText = message.querySelector(".whitespace-pre-wrap").innerHTML; | |
const sender = message.querySelector("img") ? "You" : "ChatGPT"; | |
// adds Escapes to non-MD | |
messageText = messageText.replace(/_/gs, "\_").replace(/\*/gs, "\*").replace(/\^/gs, "\^").replace(/~/gs, "\~"); // I debated adding #, > (blockquotes), and | (table) | |
// <p> element and everything in-line or inside | |
messageText = messageText.replace(/<p>(.*?)<\/p>/g, function(match, p1) { return '\n' + p1.replace(/<b>(.*?)<\/b>/g, '**$1**').replace(/<\/?b>/g, "**").replace(/<\/?i>/g, "_").replace(/<code>/g, " `").replace(/<\/code>/g, "` ") + '\n'; }); | |
markdownContent += `**${sender}:** ${Revision}${messageText.trim()}\n\n`; | |
} } | |
// Remove Span with only class declaration, there is nesting? If there is more than 5 layers, just do it manually | |
const repeatSpan = /<span class="[^"]*">([^<]*?)<\/span>/gs; markdownContent = markdownContent.replace(repeatSpan, "$1").replace(repeatSpan, "$1").replace(repeatSpan, "$1").replace(repeatSpan, "$1").replace(repeatSpan, "$1"); | |
// Code Blocks, `text` is the default catch-all (because some commands/code-blocks aren't styled/identified by ChatGPT yet) | |
markdownContent = markdownContent.replace(/<pre>.*?<code[^>]*>(.*?)<\/code>.*?<\/pre>/gs, function(match, p1) { const language = match.match(/class="[^"]*language-([^"\s]*)[^"]*"/); const languageIs = language ? language[1] : 'text'; return '\n``` ' + languageIs + '\n' + p1 + '```\n'; }); | |
//it looks redundent, but trust me lol... | |
markdownContent = markdownContent.replace(/<p>(.*?)<\/p>/g, function(match, p1) { return '\n' + p1.replace(/<b>(.*?)<\/b>/g, '**$1**').replace(/<\/?b>/g, "**").replace(/<\/?i>/g, "_").replace(/<code>/g, " `").replace(/<\/code>/g, "` ") + '\n'; }); | |
markdownContent = markdownContent.replace(/<div class="markdown prose w-full break-words dark:prose-invert dark">/gs, "").replace(/\r?\n?<\/div>\r?\n?/gs, "\n").replace(/\*\*ChatGPT:\*\* <(ol|ul)/gs, "**ChatGPT:**\n<$1").replace(/>/gs, ">").replace(/</gs, "<").replace(/&/gs, "&"); | |
const downloadLink = document.createElement("a"); | |
downloadLink.download = fileName; | |
downloadLink.href = URL.createObjectURL(new Blob([markdownContent], { type: "text/markdown" })); | |
downloadLink.style.display = "none"; | |
document.body.appendChild(downloadLink); | |
downloadLink.click(); | |
} | |
(() => {SaveChatGPTtoMD();})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment