ChatGPT对话导出工具-轻松提取聊天记录导出至本地📄

🐎一键将ChatGPT网站和国内相关镜像站的聊天记录导出为HTML或Markdown,轻松提取GPT聊天记录,让你在本地上就能使用看!

// ==UserScript==
// @name         ChatGPT对话导出工具-轻松提取聊天记录导出至本地📄
// @namespace    https://h5ma.cn/caicats
// @version      1.13
// @description  🐎一键将ChatGPT网站和国内相关镜像站的聊天记录导出为HTML或Markdown,轻松提取GPT聊天记录,让你在本地上就能使用看!
// @author       @caicats
// @match        https://chat.openai.com/*
// @match        https://new.oaifree.com/**
// @match        https://share.github.cn.com/**
// @match        https://chatgpt.com/**
// @match        https://*.oaifree.com/**
// @match        https://cc.plusai.me/**
// @match        https://chat.chatgptplus.cn/**
// @match        https://chat.rawchat.cc/**
// @match        https://chat.sharedchat.cn/**
// @match        https://chat.gptdsb.com/**
// @match        https://chat.freegpts.org/**
// @match        https://gpt.github.cn.com/**
// @match        https://chat.aicnn.xyz/**
// @match        https://*.xyhelper.com.cn/**
// @match        https://oai.aitopk.com/**
// @match        https://www.opkfc.com/**
// @match        https://bus.hematown.com/**
// @match        https://chatgpt.dairoot.cn/**
// @match        https://plus.aivvm.com/**
// @match        https://sharechat.aischat.xyz/**
// @match        https://web.tu-zi.com/**
// @match        https://chat1.2233.ai/**
// @match        https://2233.ai/**
// @match        https://yesiamai.com/**
// @match        https://www.azs.ai/**
// @match        https://oai.253282.xyz/**
// @match        https://gpt.universalbus.cn/**
// @license      MIT
// @icon         https://t1.gstatic.cn/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&size=32&url=https://chatgpt.com
// ==/UserScript==



(function() {
    'use strict';

    window.addEventListener('load', () => {
        createFloatingMenu();
    });

    function createFloatingMenu() {
        const menuContainer = document.createElement('div');
        menuContainer.id = 'floating-menu';
        menuContainer.style.position = 'fixed';
        menuContainer.style.bottom = '80px';
        menuContainer.style.right = '15px';
        menuContainer.style.zIndex = '10000';
        menuContainer.style.display = 'flex';
        menuContainer.style.flexDirection = 'column';
        menuContainer.style.alignItems = 'center';
        menuContainer.style.gap = '10px';

        // 创建提示框
        const tooltip = document.createElement('div');
        tooltip.id = 'tooltip';
        tooltip.style.position = 'fixed';
        tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
        tooltip.style.color = '#fff';
        tooltip.style.padding = '8px 12px';
        tooltip.style.borderRadius = '6px';
        tooltip.style.fontSize = '12px';
        tooltip.style.visibility = 'hidden';
        tooltip.style.zIndex = '10001';
        tooltip.style.pointerEvents = 'none';
        tooltip.style.maxWidth = '200px';
        tooltip.style.wordWrap = 'break-word';
        document.body.appendChild(tooltip);

        // Main button as expand icon
        const mainButton = document.createElement('button');
        mainButton.id = 'main-button';
        mainButton.style.width = '40px';
        mainButton.style.height = '40px';
        mainButton.style.borderRadius = '50%';
        mainButton.style.border = 'none';
        mainButton.style.backgroundColor = '#4cafa3';
        mainButton.style.color = 'white';
        mainButton.style.cursor = 'pointer';
        mainButton.style.fontSize = '26px';
        mainButton.textContent = '+';

        let isExpanded = false;
        mainButton.addEventListener('click', () => {
            isExpanded = !isExpanded;
            toggleMenu(isExpanded, menuContainer);
        });
        addTooltip(mainButton, '展开功能列表');

        // Markdown button with orange background
        const markdownButton = createMenuButton('📄', '导出为 Markdown', exportChatAsMarkdown, '#FFA500');
        addTooltip(markdownButton.querySelector('button'), '📄 导出为 Markdown');

        // HTML button with orange background
        const htmlButton = createMenuButton('🌐', '导出为 HTML', exportChatAsHTML, '#FFA500');
        addTooltip(htmlButton.querySelector('button'), '🌐 导出为 HTML');

        // Sponsor button to redirect to the specified page
        const sponsorButton = createMenuButton('❤️', '使用教程和赞赏', () => {
            window.open('https://h5ma.cn/gptdc', '_blank');
        }, '#FF6347');
        addTooltip(sponsorButton.querySelector('button'), '❤️ 使用教程和赞赏');

        // New Shop button to redirect to the specified link
        const shopButton = createMenuButton('🛒', '付费GPT库系统', () => {
            window.open('https://h5ma.cn/caicats', '_blank');
        }, '#32CD32'); // LimeGreen color for shop button
        addTooltip(shopButton.querySelector('button'), '🛒 付费GPT库系统');

        // Append buttons to the menu
        menuContainer.appendChild(mainButton);
        menuContainer.appendChild(markdownButton);
        menuContainer.appendChild(htmlButton);
        menuContainer.appendChild(sponsorButton);
        menuContainer.appendChild(shopButton);
        document.body.appendChild(menuContainer);

        // Initially hide the menu buttons
        toggleMenu(false, menuContainer);

        function addTooltip(element, text) {
            element.addEventListener('mouseenter', (event) => {
                tooltip.textContent = text;
                tooltip.style.visibility = 'visible';

                // 设置提示框在按钮左侧显示
                const rect = element.getBoundingClientRect();
                tooltip.style.left = `${rect.left - tooltip.offsetWidth - 10}px`;
                tooltip.style.top = `${rect.top + (rect.height / 2) - (tooltip.offsetHeight / 2)}px`;
            });

            element.addEventListener('mouseleave', () => {
                tooltip.style.visibility = 'hidden';
            });
        }
    }

    function createMenuButton(icon, text, onClick, bgColor) {
        const buttonContainer = document.createElement('div');
        buttonContainer.style.position = 'relative';

        const button = document.createElement('button');
        button.className = 'menu-button';
        button.style.width = '36px';
        button.style.height = '36px';
        button.style.borderRadius = '50%';
        button.style.border = 'none';
        button.style.backgroundColor = bgColor;
        button.style.color = 'white';
        button.style.cursor = 'pointer';
        button.textContent = icon;
        button.addEventListener('click', onClick);

        buttonContainer.appendChild(button);
        return buttonContainer;
    }

    function toggleMenu(expand, menuContainer) {
        const buttons = menuContainer.querySelectorAll('.menu-button');
        buttons.forEach(button => {
            button.style.display = expand ? 'block' : 'none';
        });
    }

    async function exportChatAsMarkdown() {
        try {
            let markdownContent = "# ChatGPT 对话记录\n\n";
            let allElements = document.querySelectorAll('div.flex.flex-grow.flex-col.max-w-full');

            allElements.forEach((element, index) => {
                let text = element.textContent.trim();
                if (index % 2 === 0) {
                    markdownContent += `## User\n${text}\n\n`;
                } else {
                    markdownContent += `## Assistant\n${text}\n\n`;
                }
            });

            download(markdownContent, 'chat-export.md', 'text/markdown');
        } catch (error) {
            console.error("导出为 Markdown 时出错:", error);
        }
    }

    async function exportChatAsHTML() {
        try {
            let htmlContent = "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Chat Export</title></head><body>";
            let allElements = document.querySelectorAll('div.flex.flex-grow.flex-col.max-w-full');

            allElements.forEach((element, index) => {
                let text = element.innerHTML.trim();
                if (index % 2 === 0) {
                    htmlContent += `<h2>User</h2><div>${text}</div>`;
                } else {
                    htmlContent += `<h2>Assistant</h2><div>${text}</div>`;
                }
            });

            htmlContent += "</body></html>";
            download(htmlContent, 'chat-export.html', 'text/html');
        } catch (error) {
            console.error("导出为 HTML 时出错:", error);
        }
    }

    function download(data, filename, type) {
        const blob = new Blob([data], {type: type});
        const a = document.createElement('a');
        const url = URL.createObjectURL(blob);
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }
})();