Skip to content

Instantly share code, notes, and snippets.

@dreness
Last active July 10, 2024 03:15
Show Gist options
  • Save dreness/bd45eee1f5dbb3f892eb4802745bfd74 to your computer and use it in GitHub Desktop.
Save dreness/bd45eee1f5dbb3f892eb4802745bfd74 to your computer and use it in GitHub Desktop.
Tampermonkey script for use with chatgpt.com to add a "Save code" button below the "Copy code" button
// ==UserScript==
// @name Save Code Snippets
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Add a button to save code snippets from ChatGPT responses
// @author dre
// @match https://chat.openai.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
// @grant GM_download
// ==/UserScript==
/* Goal is to add a "Save code" button to each code block in the ChatGPT response,
right below the 'Copy code' button
The general shape of the DOM is as follows:
page
prompt_container
prompt_text
response_container
response_text
response_code_container?
response_code_header
language_name
copy_code_button
save_code_button
response_code
TODO
- try to suggest an appropriate file name extension
*/
(function () {
'use strict';
function downloadCodeSnippet(code, fileName) {
const blob = new Blob([code], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// Add a "Save code" button below each "Copy code" button
function addSaveButton() {
const codeBlocks = document.querySelectorAll('pre');
codeBlocks.forEach(codeBlock => {
// check the codeBlock for an existing save button, which will have the class 'save-code-button'.
// If present, skip this iteration.
if (codeBlock.parentNode.querySelector('.save-code-button')) {
return;
}
const buttons = codeBlock.parentNode.querySelectorAll('button');
buttons.forEach(button => {
if (button.textContent === 'Copy code') {
const saveButton = document.createElement('button');
saveButton.className = 'flex gap-1 items-center save-code-button';
saveButton.onclick = () => {
const code =
button.parentElement.parentElement.parentElement.parentElement
.children[1].innerText;
let chatId = window.location.pathname.split('/').pop();
let fileName = prompt('Enter the filename:', 'code.txt');
if (!fileName) {
return;
}
if (chatId) {
fileName = `${chatId}_${fileName}`;
}
downloadCodeSnippet(code, fileName);
};
const svg = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg'
);
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svg.setAttribute('width', '24');
svg.setAttribute('height', '24');
svg.setAttribute('fill', 'none');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('class', 'icon-sm');
const path = document.createElementNS(
'http://www.w3.org/2000/svg',
'path'
);
path.setAttribute('fill', 'white');
path.setAttribute(
'd',
'M7.93184 18.7313C8.18368 18.7313 8.41618 18.6677 8.86336 18.1979L15.5295 11.0094C15.7181 10.8074 15.8637 10.5991 15.8637 10.3249C15.8637 9.93867 15.5627 9.7282 15.1999 9.7282L11.059 9.7282L11.059 1.69172C11.059 0.591447 10.491 0 9.42586 0L6.35145 0C5.27461 0 4.71832 0.591447 4.71832 1.69172L4.71832 9.7282L0.658832 9.7282C0.296017 9.7282 0 9.93867 0 10.3233C0 10.5975 0.144727 10.8107 0.318401 11.0094L7.00114 18.1979C7.4366 18.6568 7.68082 18.7313 7.93184 18.7313Z'
);
svg.appendChild(path);
saveButton.appendChild(svg);
saveButton.appendChild(document.createTextNode('Save code'));
button.parentNode.appendChild(saveButton);
}
});
});
}
// Add save button to existing code blocks
addSaveButton();
// Add mutation observer to detect new code blocks
const observer = new MutationObserver(mutations => {
observer.disconnect();
mutations.forEach(() => {
addSaveButton();
});
observer.observe(document.body, { childList: true, subtree: true });
});
observer.observe(document.body, { childList: true, subtree: true });
})();
@dreness
Copy link
Author

dreness commented Jul 8, 2024

save-code-demo.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment