ChatGPT Export to Markdown (Named)

Adds a button to export ChatGPT conversations as Markdown with the chat's name as the file name.

// ==UserScript==
// @name          ChatGPT Export to Markdown (Named)
// @description   Adds a button to export ChatGPT conversations as Markdown with the chat's name as the file name.
// @author        chatgpt.js
// @namespace     https://chatgpt.js.org
// @version       1.0
// @license       MIT
// @match         *://chatgpt.com/*
// @icon          https://cdn.jsdelivr.net/npm/@mdi/svg/svg/content-save.svg
// @require       https://cdn.jsdelivr.net/npm/@kudoai/[email protected]/dist/chatgpt.min.js
// @grant         GM_getValue
// @grant         GM_setValue
// @noframes
// ==/UserScript==

(async () => {
    // Ensure chatgpt.js is loaded
    await chatgpt.isLoaded();

    // Add the export button with a floppy disk icon
    const button = document.createElement('button');
    button.id = 'export-to-markdown-btn';
    button.style.position = 'fixed';
    button.style.bottom = '20px';
    button.style.right = '20px';
    button.style.zIndex = '9999';
    button.style.backgroundColor = '#4CAF50';
    button.style.border = 'none';
    button.style.padding = '10px';
    button.style.borderRadius = '50%';
    button.style.cursor = 'pointer';

    // Add floppy disk icon to the button
    const floppyIcon = document.createElement('img');
    floppyIcon.src = 'https://cdn.jsdelivr.net/npm/@mdi/svg/svg/content-save.svg';
    floppyIcon.width = 24;
    button.appendChild(floppyIcon);

    // Append the button to the body
    document.body.appendChild(button);

    // Button click handler
    button.addEventListener('click', async () => {
        try {
            // Fetch the current conversation data
            const chatData = await chatgpt.getChatData("active", ["msg"], "both");
            const chatTitleData = await chatgpt.getChatData("active", "title");

            // Use the chat's title or a fallback
            const chatTitle = chatTitleData.title || 'ChatGPT_Conversation';
            const sanitizedTitle = chatTitle.replace(/[<>:"/\\|?*]+/g, ''); // Remove invalid filename characters

            // Convert the conversation data to a markdown format
            let markdownContent = `# ${chatTitle}\n\n`;
            chatData.forEach((msg, index) => {
                markdownContent += `### Message ${index + 1}\n\n`;
                markdownContent += `**User:** ${msg.user}\n\n`;
                markdownContent += `**ChatGPT:** ${msg.chatgpt}\n\n---\n`;
            });

            // Create a Blob object from the markdown content
            const blob = new Blob([markdownContent], { type: 'text/markdown' });

            // Create a link element to download the markdown file
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            link.download = `${sanitizedTitle}.md`;
            link.click();

            // Notify the user
            chatgpt.notify('✅ Exported to Markdown successfully!', 'topRight', 2);
        } catch (error) {
            chatgpt.notify('❌ Failed to export conversation!', 'topRight', 2);
            console.error('Export to Markdown failed:', error);
        }
    });
})();