-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGPT2MD.js
57 lines (49 loc) · 3.25 KB
/
GPT2MD.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
function SaveChatGPTtoMD() {
const chatMessages = document.querySelectorAll(".text-base.md\\:px-5");
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 - " + pageTitle + ' - ' + dateString + ".md";
let markdownContent = "---\nmarp: false\n---\n";
for (const message of chatMessages) {
let Revision = '';
const revisionElement = message.querySelector(".text-xs .flex-grow");
if (revisionElement && revisionElement.innerHTML) {
Revision = `Edit Revision: **${revisionElement.innerHTML}**\n`;
}
if (message.querySelector("div > div > div > .whitespace-pre-wrap")) {
let messageText = message.querySelector(
"div > div > div > .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---\n---\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';
});
markdownContent = markdownContent.replace(/<p>(.*?)<\/p>/g, function(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();
}