Skip to content

Instantly share code, notes, and snippets.

@macrat
Created April 21, 2023 11:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save macrat/802e108d2084d36f15e109a0d2d0dd61 to your computer and use it in GitHub Desktop.
Save macrat/802e108d2084d36f15e109a0d2d0dd61 to your computer and use it in GitHub Desktop.
A bookmarklet for copying ChatGPT history as Markdown text

Bookmarklet for copying ChatGPT history

javascript:(()=>{let s=x=>x.replace(/([^\\]|^)\n/,'$1  \n').replace('<','&lt;').replace('>','&gt;'),f=e=>(({'#text':e=>s(e.textContent),DIV:g('\n\n'),P:g(''),OL:e=>[...e.childNodes].map((x,i)=>`${i+(e.start??1)}. ${f(x).replace(/\n/,'\n  '+' '.repeat(`${i}`.length))}`).join('\n'),UL:e=>[...e.childNodes].map(x=>`- ${f(x).replace(/\n/,'\n  ')}`).join('\n'),LI:g(''),TABLE:e=>`|${[...e.querySelectorAll('thead th')].map(f).join('|')}|\n|${[...e.querySelectorAll('thead th')].map(x=>'---').join('|')}|\n`+[...e.querySelectorAll('tbody tr')].map(x=>`|${[...x.children].map(g('')).join('|')}|`).join('\n'),PRE:e=>'```'+e.querySelector('.hljs').className.replace(/^.*language-(\S+).*$/,'$1')+'\n'+e.querySelector('.hljs').innerText.replace(/([^\n])$/,'$1\n')+'```',CODE:e=>'`'+e.innerText+'`',STRONG:e=>`**${g('')(e)}**`,EM:e=>`_${g('')(e)}_`,DEL:e=>`<del>${g('')(e)}</del>`,IMG:e=>`![${e.alt}](${e.src})`})[e.nodeName]??(e=>s(e.innerText)))(e),g=j=>e=>[...e.childNodes].map(f).join(j),h=[...document.querySelectorAll('.group.w-full')].map(e=>`[__${e.classList.contains('bg-gray-50')?'Assistant':'User'}__]\n${g('\n\n')(e.querySelector('.whitespace-pre-wrap'))}`).join('\n\n');console.log(h);navigator.clipboard.writeText(h).then(()=>alert("copied!")).catch(alert)})()

Usage

  1. Make a bookmark using above text as URL.

  2. Open your chat page in ChatGPT web interface.

  3. Open your bookmarklet.

  4. Paste your clipboard to wherever you want.

(()=>{
let s = x => x.replace(/([^\\]|^)\n/,'$1 \n').replace('<','&lt;').replace('>','&gt;'),
f = e => (({
'#text': e => s(e.textContent),
DIV: g('\n\n'),
P: g(''),
OL: e => [...e.childNodes].map((x,i)=>`${i+(e.start??1)}. ${f(x).replace(/\n/,'\n '+' '.repeat(`${i}`.length))}`).join('\n'),
UL: e => [...e.childNodes].map(x=>`- ${f(x).replace(/\n/,'\n ')}`).join('\n'),
LI: g(''),
TABLE: e => `|${
[...e.querySelectorAll('thead th')].map(f).join('|')
}|\n|${
[...e.querySelectorAll('thead th')].map(x=>'---').join('|')
}|\n`+[...e.querySelectorAll('tbody tr')].map(x=>`|${[...x.children].map(g('')).join('|')}|`).join('\n'),
PRE: e => '```' + e.querySelector('.hljs').className.replace(/^.*language-(\S+).*$/,'$1') + '\n' + e.querySelector('.hljs').innerText.replace(/([^\n])$/,'$1\n') + '```',
CODE: e => '`'+e.innerText+'`',
STRONG: e => `**${g('')(e)}**`,
EM: e => `_${g('')(e)}_`,
DEL: e => `<del>${g('')(e)}</del>`,
IMG: e => `![${e.alt}](${e.src})`,
})[e.nodeName] ?? (e => s(e.innerText)))(e),
g = j => e => [...e.childNodes].map(f).join(j),
h = [...document.querySelectorAll('.group.w-full')]
.map(e => `[__${e.classList.contains('bg-gray-50')?'Assistant':'User'}__]\n${g('\n\n')(e.querySelector('.whitespace-pre-wrap'))}`)
.join('\n\n');
console.log(h);
navigator.clipboard.writeText(h).then(()=>alert("copied!")).catch(alert);
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment