diff --git a/background.js b/background.js new file mode 100644 index 0000000..e004326 --- /dev/null +++ b/background.js @@ -0,0 +1,29 @@ +chrome.webRequest.onCompleted.addListener( + (details) => { + if ( + details.url.includes( + "https://chat.openai.com/backend-api/conversations?" + ) + ) { + chrome.tabs.sendMessage(details.tabId, { + message: "conversations_data_fetched", + }); + } + }, + { urls: [""] } + ); + + chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.message === "fetch_conversations_data") { + fetch(request.url) + .then((response) => response.json()) + .then((data) => { + sendResponse({ data: data.items }); + }) + .catch((error) => { + console.error("Error fetching conversations data:", error); + }); + return true; + } + }); + \ No newline at end of file diff --git a/content.js b/content.js new file mode 100644 index 0000000..e553b33 --- /dev/null +++ b/content.js @@ -0,0 +1,127 @@ +console.log('content.js is running'); + +// 向每个会话前添加复选框 +// 向每个会话前添加复选框 +// function addCheckboxes() { +// const conversations = document.querySelectorAll( +// '.flex.flex-col.gap-2.pb-2.text-gray-100.text-sm > .flex.py-3.px-3.items-center.gap-3.relative.rounded-md.hover\\:bg-\\[\\#2A2B32\\].cursor-pointer.break-all.hover\\:pr-4.group' +// ); + +// conversations.forEach((conversation) => { +// const checkbox = document.createElement('input'); +// checkbox.type = 'checkbox'; +// checkbox.className = 'conversation-checkbox'; +// conversation.insertBefore(checkbox, conversation.firstChild); +// }); +// } + +document.addEventListener("fetch", (event) => { + const response = event.detail.response; + + if (response) { + console.log("Result found:", response); + // 在这里执行你的逻辑 + } + }); + + + +function addCheckboxes() { + console.log(`try to addCheckboxes...`); + const conversations = document.querySelectorAll( + '.flex.flex-col.gap-2.pb-2.text-gray-100.text-sm > .flex.py-3.px-3.items-center.gap-3.relative.rounded-md.hover\\:bg-\\[\\#2A2B32\\].cursor-pointer.break-all.hover\\:pr-4.group' + ); + + conversations.forEach((conversation) => { + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.className = 'conversation-checkbox'; + checkbox.addEventListener('click', (event) => { + event.stopPropagation(); + }); + conversation.insertBefore(checkbox, conversation.firstChild); + }); + } + + + + + + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.message === 'add_checkboxes') { + addCheckboxes(); + } else if (request.message === 'delete_selected_conversations') { + deleteSelectedConversations(); + } +}); + +async function fetchAllConversations(offset = 0, limit = 20) { + const response = await fetch( + `https://chat.openai.com/backend-api/conversations?offset=${offset}&limit=${limit}` + ); + const data = await response.json(); + const conversations = data.items; + + if (conversations.length === limit) { + const nextConversations = await fetchAllConversations(offset + limit, limit); + return [...conversations, ...nextConversations]; + } + + return conversations; + } + + async function buildTitleToIdMap() { + const conversations = await fetchAllConversations(); + const titleToIdMap = {}; + + conversations.forEach((conversation) => { + const title = conversation.title; + if (titleToIdMap[title]) { + titleToIdMap[title].push(conversation.id); + } else { + titleToIdMap[title] = [conversation.id]; + } + }); + + return titleToIdMap; + } + + async function deleteSelectedConversations() { + const titleToIdMap = await buildTitleToIdMap(); + const checkboxes = document.querySelectorAll('.conversation-checkbox:checked'); + const conversationIds = []; + + checkboxes.forEach((checkbox) => { + const titleElement = checkbox.parentElement.querySelector('.text-ellipsis'); + const title = titleElement.textContent; + const conversationId = titleToIdMap[title].shift(); + + if (conversationId) { + conversationIds.push(conversationId); + } + }); + + await Promise.all( + conversationIds.map(async (id) => { + console.log(`try to delete conversation with ID: ${id}`); + await fetch(`https://chat.openai.com/backend-api/conversation/${id}`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + status: 'deleted', + }), + }); + + console.log(`Deleted conversation with ID: ${id}`); + }) + ); + + location.reload(); + } + + + + diff --git a/icon48.png b/icon48.png new file mode 100644 index 0000000..45eef6b Binary files /dev/null and b/icon48.png differ diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..62ff07b --- /dev/null +++ b/manifest.json @@ -0,0 +1,28 @@ +{ + "manifest_version": 2, + "name": "Bulk Delete ChatGPT Conversations", + "version": "1.0", + "description": "A Chrome extension to bulk delete ChatGPT conversations.", + "icons": { + "48": "icon48.png" + }, + "permissions": [ + "activeTab", + "storage", + "declarativeContent", + "webRequest", + "webRequestBlocking", + "" + ], + "browser_action": { + "default_icon": "icon48.png", + "default_popup": "popup.html" + }, + "content_scripts": [ + { + "matches": ["https://chat.openai.com/*"], + "js": ["content.js"] + } + ] + } + \ No newline at end of file diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..b023e5d --- /dev/null +++ b/popup.html @@ -0,0 +1,16 @@ + + + + + + Bulk Delete ChatGPT Conversations + + + + + + + + + + diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..562b47b --- /dev/null +++ b/popup.js @@ -0,0 +1,14 @@ +// popup.js +document.getElementById('add_checkboxes').addEventListener('click', () => { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, { message: 'add_checkboxes' }); + }); + }); + + document.getElementById('delete_selected').addEventListener('click', () => { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + chrome.tabs.sendMessage(tabs[0].id, { message: 'delete_selected_conversations' }); + }); + }); + + \ No newline at end of file