Forked from equinoxmatt/gist:46993dd65b9a7f89f47af457f77f40c7
Created
July 6, 2024 18:57
-
-
Save jmhublar/6f7f023413bde1c2e428d5e9b3ccbe6e to your computer and use it in GitHub Desktop.
TamperMonkey script for removing multiple chats in ChatGPT
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
// ==UserScript== | |
// @name ChatGPT | |
// @version 0.1 | |
// @description Allow deleting multiple chats at a time. | |
// @match https://chat.openai.com/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// Style definitions for checkboxes and the delete button | |
const css = ` | |
li.relative[data-projection-id] { | |
position: relative; | |
padding-left: 40px; /* Make room for checkbox */ | |
} | |
li.relative[data-projection-id] .custom-checkbox { | |
position: absolute; | |
left: 5px; /* Position from the left edge of the LI */ | |
top: 50%; | |
transform: translateY(-50%); | |
z-index: 16; /* Ensure it's on top of the LI but below other potential overlays */ | |
display: none; /* Hide the checkbox initially */ | |
} | |
li.relative[data-projection-id]:hover .custom-checkbox, | |
li.relative[data-projection-id] .custom-checkbox:checked { | |
display: block; /* Show the checkbox on hover or when checked */ | |
} | |
`; | |
// Function to add the CSS to the document head | |
function addStyles() { | |
const style = document.createElement('style'); | |
style.type = 'text/css'; | |
style.innerHTML = css; | |
document.head.appendChild(style); | |
} | |
// Function to add checkboxes to each list item | |
function addCheckboxes() { | |
document.querySelectorAll('li.relative[data-projection-id]').forEach(item => { | |
if (!item.querySelector('.custom-checkbox')) { | |
const checkbox = document.createElement('input'); | |
checkbox.type = 'checkbox'; | |
checkbox.classList.add('custom-checkbox'); | |
item.insertBefore(checkbox, item.firstChild); | |
} | |
}); | |
} | |
// Function to add a delete button to the page | |
function addDeleteButton() { | |
const targetContainer = document.querySelector('div.gap-2:nth-child(3)'); | |
if (targetContainer && !document.getElementById('delete-button')) { | |
const deleteButton = document.createElement('button'); | |
deleteButton.id = 'delete-button'; | |
deleteButton.textContent = 'Delete'; | |
deleteButton.style.display = 'block'; | |
deleteButton.addEventListener('click', handleDeleteAction); | |
targetContainer.appendChild(deleteButton); | |
} | |
} | |
// Function to update the visibility of the delete button | |
function updateDeleteButtonVisibility() { | |
const anyChecked = document.querySelectorAll('li.relative[data-projection-id] .custom-checkbox:checked').length > 0; | |
const deleteButton = document.getElementById('delete-button'); | |
if (deleteButton) { | |
deleteButton.style.display = anyChecked ? 'block' : 'none'; | |
} | |
} | |
// Function to fetch the access token | |
function fetchAccessToken() { | |
return fetch('https://chat.openai.com/api/auth/session', { | |
credentials: 'include' | |
}) | |
.then(response => response.json()) | |
.then(data => data.accessToken) | |
.catch(error => { | |
console.error('Error fetching access token:', error); | |
return null; | |
}); | |
} | |
// Initialization function | |
function init() { | |
addStyles(); | |
addCheckboxes(); | |
setTimeout(() => { | |
addDeleteButton(); | |
updateDeleteButtonVisibility(); | |
}, 0); | |
} | |
// Delete action handler | |
function handleDeleteAction() { | |
fetchAccessToken().then(accessToken => { | |
if (!accessToken) { | |
console.error('No access token retrieved.'); | |
return; | |
} | |
document.querySelectorAll('li.relative[data-projection-id] .custom-checkbox:checked').forEach(checkbox => { | |
const parentLi = checkbox.closest('li.relative[data-projection-id]'); | |
const href = parentLi.querySelector('a').getAttribute('href'); | |
const id = href.substring(href.lastIndexOf('/') + 1); | |
fetch('https://chat.openai.com/backend-api/conversation/' + id, { | |
method: 'PATCH', | |
headers: { | |
'Content-Type': 'application/json', | |
'Authorization': `Bearer ${accessToken}` | |
}, | |
body: JSON.stringify({ is_visible: false }) | |
}) | |
.then(response => response.json()) | |
.then(data => { | |
console.log('Delete successful', data); | |
parentLi.remove(); | |
}) | |
.catch(error => { | |
console.error('Error:', error); | |
}); | |
}); | |
}); | |
} | |
// Event listener for checkbox state changes | |
document.addEventListener('change', e => { | |
if (e.target.classList.contains('custom-checkbox')) { | |
updateDeleteButtonVisibility(); | |
} | |
}); | |
// Mutation observer for dynamically added content | |
const observer = new MutationObserver(mutations => { | |
mutations.forEach(mutation => { | |
if (mutation.addedNodes.length) { | |
addDeleteButton(); | |
addCheckboxes(); | |
updateDeleteButtonVisibility(); | |
} | |
}); | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
// Start the script based on the document's loading state | |
if (document.readyState === 'loading') { | |
window.addEventListener('DOMContentLoaded', init); | |
} else { | |
init(); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment