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.5.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==

(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

    GM_registerMenuCommand("Get conversation titles", ()=>{
        const conversationList = getConversationList();
        conversationList.forEach(conversation =>{
            console.log(conversation.id, conversation);
            GM_setValue(conversation.id, conversation);
        });
    });

    GM_registerMenuCommand("List conversations in TSV", ()=>{
        const textarea = createTextarea();
        const idArray = GM_listValues();
        console.log(idArray);
        const tsv = idArray.map( id =>{
            const conversation = GM_getValue(id);
            return [conversation.id, conversation.title, conversation.projectionId].join("\t");
        });
        textarea.value = tsv.join("\n");
    });

    function getConversationList(){
        var conversationList = [];
        //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");
        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;
                    conversationList.push({id:id, title:title, projectionId:projectionId});
                }//if
            }//for
        });//forEach
        return conversationList;
    }//getConversationList
    // Your code here...
})();

QingJ © 2025

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