ChatGPT Conversation Lister

Retrieves the titles and unique identifiers of conversations in ChatGPT's web interface. Intended for listing and organization purposes only.

当前为 2023-08-10 提交的版本,查看 最新版本

// ==UserScript==
// @name         ChatGPT Conversation Lister
// @namespace    https://moukaeritai.work/chatgpt-conversation-lister
// @version      0.7.3.20230810
// @description  Retrieves the titles and unique identifiers of conversations in ChatGPT's web interface. Intended for listing and organization purposes only.
// @author       Takashi SASAKI https://twitter.com/TakashiSasaki
// @match        https://chat.openai.com/
// @match        https://chat.openai.com/c/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=openai.com
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @license      MIT
// ==/UserScript==

/*
## Detailed Description

ChatGPT Conversation Lister is a UserScript designed to get and list the conversations within the ChatGPT's web interface.
Specifically, this UserScript retrieves only the titles and unique identifiers of the chat histories, and it does not obtain or interact with the content of the conversations.
By obtaining the titles and unique identifiers, users can easily keep track of their conversations, arrange them in a systematic manner, and retrieve them as needed,
including pasting them into tools such as Google Sheets or Excel for further organization and analysis.
This tool is intended solely for listing and organization, and it does not alter the conversations in any way.
Importantly, the UserScript gathers information directly from the ChatGPT web pages that the user is viewing, and its execution does not initiate any new communications or network requests.

### How to Use ChatGPT Conversation Lister

1. **Access ChatGPT's web page** with ChatGPT_ConversationLister.user.js installed on your browser.
2. **Open the Tampermonkey or Greasemonkey menu** and you should see the item created by ChatGPT_ConversationLister.user.js.
3. **Choose an option like "List conversations in TSV"** from the menu, and a dialog with the results will be displayed.
4. **Double-click the result** to copy it to the clipboard. Pressing the ESC key will close the dialog.

These steps provide a simple and efficient way to organize and manage your conversations within the ChatGPT interface using the ChatGPT_ConversationLister.user.js script. It ensures the integrity of the conversation content while allowing easy access and retrieval as needed.

### This script is available at
- **GitHub Gist**: [ChatGPT_ConversationLister.user.js](https://gist.github.com/TakashiSasaki/e9d01e569ec339d01bd7d43188b15673)
- **Greasy Fork镜像**: [ChatGPT_ConversationLister.user.js](https://gf.qytechs.cn/ja/scripts/472814)
*/

(function() {
    'use strict';

    const container = document.createElement('div');
    container.id = "tampermonkeyDialogDiv";
    document.body.appendChild(container);
    const shadowRoot = container.attachShadow({mode: 'open'});
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') {
            while(shadowRoot.firstChild){
                shadowRoot.removeChild(shadowRoot.firstChild);
            }//while
        }//if
    });

    function createDialog(){
        // ダイアログ要素を作成
        var dialog = document.createElement('div');
        dialog.style.cssText = `
  position: fixed;
  top: 10%;
  left: 10%;
  width: 80%;
  height: 80%;
  max-height:80%;
  background: white;
  padding: 10px;
  border: 1px solid black;
  z-index: 10000;
  border-radius: 15px;
  box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
  overflow: auto;
`;

        var closeButton = document.createElement('button');
        closeButton.innerHTML = 'Close';
        closeButton.style.cssText = 'position: absolute; top: 0; right: 0; user-select: none';

        closeButton.addEventListener('click', function() {
            while(shadowRoot.firstChild){
                shadowRoot.removeChild(shadowRoot.firstChild);
            }//while
        });
        dialog.appendChild(closeButton);

        shadowRoot.appendChild(dialog);
        return dialog;
    }//createDialog

    function createTextarea(){
        var textarea = document.createElement('textarea');
        textarea.setAttribute("readonly", "readonly");
        textarea.style.cssText = `
  position: fixed;
  top: 10%;
  left: 10%;
  width: 80%;
  height: 80%;
  max-height:80%;
  background: white;
  padding: 10px;
  border: 1px solid black;
  z-index: 10000;
  border-radius: 15px;
  box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
  overflow: auto;
`;
        textarea.addEventListener("dblclick", (event)=>{
            event.target.select();
            document.execCommand('copy');
        });
        shadowRoot.appendChild(textarea);
        return textarea;
    }//createTextarea


    var lastScrollTop = 0;
    var originalScrollHeight = 0;
    var observer = null;
    GM_registerMenuCommand("Continuous scrolling on conversation list", ()=>{
        const div = document.querySelector("#__next > div.overflow-hidden.w-full.h-full.relative.flex > div.dark.flex-shrink-0.overflow-x-hidden > div > div > div > nav > div.overflow-y-auto");
        console.log(div);
        const style = window.getComputedStyle(div);
        console.log(style);
        if(style.overflowY === 'auto') {
            console.log(style.overflowY);
            if(!observer) {
                observer = new MutationObserver((mutationList, observer)=>{
                    mutationList.forEach(mutation=>{
                        //if(mutation.target !== div) return;
                        //console.log(mutation.target);
                        if(lastScrollTop != div.scrollTop) {
                            console.log("lastScrollTop", lastScrollTop, "scrollTop", div.scrollTop);
                            lastScrollTop = div.scrollTop;
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 2}, 200);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 3}, 300);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 4}, 400);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 5}, 500);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 6}, 600);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 7}, 700);
                            setTimeout(()=> {div.scrollTop = div.scrollHeight * 8}, 800);
                        }//if
                    });//forEach
                });//MutationObserver
            }//if
            observer.observe(div, {
                childList : true,
                attributes: true,
                subtree: true
            });
            originalScrollHeight = div.scrollHeight;
            console.log("originalScrollHeight", originalScrollHeight);
            setTimeout(()=> {div.scrollTop = div.scrollHeight * 2}, 200);
            setTimeout(()=> {div.scrollTop = div.scrollHeight * 3}, 300);
            setTimeout(()=> {div.scrollTop = div.scrollHeight * 4}, 400);
        }//if
    });//GM_registerMenuCommand

    GM_registerMenuCommand("List conversations in TSV", ()=>{
        updateConversationList();
        const textarea = createTextarea();
        const idArray = GM_listValues();
        const tsv = idArray.map( id =>{
            const conversation = GM_getValue(id);
            return [conversation.id, conversation.title, conversation.projectionId];
        });
        const tsvSorted = tsv.sort( (a,b) => {
            return parseInt(a[2] - parseInt(b[2]));
        }//sort
                                  );
        const tsvJoined = tsvSorted.map((x)=> x.join("\t"));
        textarea.value = tsvJoined.join("\n");
    });

    function updateConversationList(){
        //const div = document.querySelector("#__next div nav div div");
        //const div = document.querySelector("#__next > div.overflow-hidden.w-full.h-full.relative.flex.z-0 > div.flex-shrink-0.overflow-x-hidden > div > div > div > nav > div.flex-col > div > div");
        const div = document.querySelector("#__next > div.overflow-hidden.w-full.h-full.relative.flex > div.dark.flex-shrink-0.overflow-x-hidden > div > div > div > nav > div.overflow-y-auto");
        console.log(div);
        const liNodes = div.querySelectorAll("li");
        console.log(liNodes);
        liNodes.forEach((li)=>{
            console.log(li);
            for (var key in li) {
                if (key.startsWith('__reactProps')) {
                    const id = li[key].children.props.id;
                    const title = li[key].children.props.title;
                    const projectionId = li.dataset.projectionId;
                    console.log(id, title,projectionId);
                    if(!id) continue;
                    if(!title) continue;
                    GM_setValue(id, {id:id, title:title, projectionId:projectionId});
                }//if
            }//for
        });//forEach
    }//updateConversationList
    // Your code here...
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址