Index ChatGPT chats to local browser storage (IndexedDB)
Tampermonkey script
// ==UserScript==
// @name ChatGPT Chat Extractor
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Extract ChatGPT chats to IndexedDB
// @author Dave Hague
// @match https://chatgpt.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('ChatGPTChats', 1);
request.onupgradeneeded = function(event) {
const db = event.target.result;
if (!db.objectStoreNames.contains('links')) {
const objectStore = db.createObjectStore('links', { keyPath: 'id', autoIncrement: true });
objectStore.createIndex('url', 'url', { unique: true });
}
};
request.onsuccess = function(event) { resolve(event.target.result); };
request.onerror = function(event) { reject('Database error: ' + event.target.errorCode); };
});
}
function checkURLExists(db, url) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['links'], 'readonly');
const objectStore = transaction.objectStore('links');
const index = objectStore.index('url');
const request = index.get(url);
request.onsuccess = function(event) {
resolve(!!event.target.result);
};
request.onerror = function(event) {
reject('Check error: ' + event.target.errorCode);
};
});
}
function saveDataToDB(db, data) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['links'], 'readwrite');
const objectStore = transaction.objectStore('links');
const request = objectStore.add(data);
request.onsuccess = function() { resolve('Data saved successfully'); };
request.onerror = function(event) { reject('Save error: ' + event.target.errorCode); };
});
}
async function extractAndSaveData() {
try {
const elements = document.querySelectorAll('a.flex.items-center');
console.log('Elements found:', elements.length);
const today = new Date().toISOString().split('T')[0];
const db = await initDB();
let count = 0;
for (const el of elements) {
const url = el.href;
const innerTextElement = el.querySelector('div.relative.grow.overflow-hidden.whitespace-nowrap');
const innerText = innerTextElement ? innerTextElement.innerText.trim() : '';
if (!url || !innerText) {
continue;
}
const data = { url, innerText, firstSeen: today };
const exists = await checkURLExists(db, url);
if (!exists) {
await saveDataToDB(db, data);
console.log('New item found and saved:', data);
count++;
}
}
console.log('Data extraction and saving completed. ', count, 'NEW items found and saved');
} catch (error) {
console.error(error);
}
}
window.onload = function() {
console.log('Page fully loaded, running extraction script.');
setTimeout(() => {
extractAndSaveData();
}, 5000); // Delay of 5 seconds to ensure dynamic content is loaded
};
// Uncomment the below section for grabbing history (manually scrolling down first)
/*
function addButton() {
const button = document.createElement('button');
button.innerText = 'Extract Data';
button.style.position = 'fixed';
button.style.top = '10px';
button.style.right = '10px';
button.style.zIndex = 1000;
button.style.padding = '10px';
button.style.backgroundColor = '#4CAF50';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.onclick = extractAndSaveData;
document.body.appendChild(button);
}
window.onload = function() {
console.log('Page fully loaded, adding trigger button.');
addButton();
};
*/
})();
JS Bookmarklet
javascript:(function() {
// Function to initialize the IndexedDB
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open('LinkedInDataDB', 1);
request.onupgradeneeded = function(event) {
const db = event.target.result;
if (!db.objectStoreNames.contains('links')) {
db.createObjectStore('links', { keyPath: 'id', autoIncrement: true });
}
};
request.onsuccess = function(event) {
resolve(event.target.result);
};
request.onerror = function(event) {
reject('Database error: ' + event.target.errorCode);
};
});
}
// Function to save data to the IndexedDB
function saveDataToDB(db, data) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['links'], 'readwrite');
const objectStore = transaction.objectStore('links');
const request = objectStore.add(data);
request.onsuccess = function() {
resolve('Data saved successfully');
};
request.onerror = function(event) {
reject('Save error: ' + event.target.errorCode);
};
});
}
// Function to extract data and save it to IndexedDB
async function extractAndSaveData() {
try {
const elements = document.querySelectorAll('a.flex.items-center.gap-2.p-2');
const results = Array.from(elements).map(el => {
const url = el.href;
const innerTextElement = el.querySelector('div.relative.grow.overflow-hidden.whitespace-nowrap');
const innerText = innerTextElement ? innerTextElement.innerText.trim() : '';
return { url, innerText };
});
const db = await initDB();
for (const result of results) {
await saveDataToDB(db, result);
}
console.log('All data saved successfully', results);
} catch (error) {
console.error(error);
}
}
extractAndSaveData();
})();