Chat GPT Code Export Button

Adds Export button to code blocks in ChatGPT responses, prompts user to save code as file with predefined filename based on coding language detected from the code block's class name.

目前为 2024-07-04 提交的版本。查看 最新版本

// ==UserScript==
// @name         Chat GPT Code Export Button
// @namespace    http://tampermonkey.net/
// @version      2024/07/03
// @license      MIT
// @description  Adds Export button to code blocks in ChatGPT responses, prompts user to save code as file with predefined filename based on coding language detected from the code block's class name.
// @author       Muffin & Arcadie
// @match        https://chatgpt.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Function to add "Export" button to existing code headers
    function addExportButtonToHeaders() {
        const codeHeaders = document.querySelectorAll('.flex.items-center.relative.text-token-text-secondary.bg-token-main-surface-secondary.px-4.py-2.text-xs.font-sans.justify-between.rounded-t-md');

        codeHeaders.forEach(header => {
            // Check if "Export" button is already added
            if (header.querySelector('.export-button')) {
                return; // Skip if already added
            }

            // Find the language label
            const languageLabel = header.querySelector('span');

            // Create the "Export" button
            const exportButton = document.createElement('button');
            exportButton.innerText = 'Export';
            exportButton.classList.add('export-button'); // Add a class for styling
            exportButton.style.padding = '8px 16px';
            exportButton.style.marginRight = '8px'; // Adjust spacing if necessary
            exportButton.style.border = 'none';
            exportButton.style.borderRadius = '4px';
            exportButton.style.backgroundColor = '#e3e3e3';
            exportButton.style.color = '#333';
            exportButton.style.cursor = 'pointer';
            exportButton.style.transition = 'background-color 0.3s';

            // Insert "Export" button after the language label
            languageLabel.parentNode.insertBefore(exportButton, languageLabel.nextSibling);

            // Add click event listener for the "Export" button
            exportButton.addEventListener('click', () => {
                const codeBlock = header.parentElement.querySelector('pre code'); // Assuming structure, adjust as needed
                const language = languageLabel.textContent.trim().toLowerCase(); // Extract language
                exportCode(codeBlock, language); // Call export function
            });
        });
    }

    // Function to open File Explorer for saving the code as file
    async function exportCode(codeBlock, language) {
        let fileName;
        let fileExtension;
        let mimeType;

        // Determine filename, extension, and MIME type based on language
        switch (language) {
            case 'javascript':
            case 'js':
                fileName = 'script';
                fileExtension = '.js';
                mimeType = 'application/javascript';
                break;
            case 'html':
                fileName = 'index';
                fileExtension = '.html';
                mimeType = 'text/html';
                break;
            case 'css':
                fileName = 'styles';
                fileExtension = '.css';
                mimeType = 'text/css';
                break;
            case 'python':
            case 'py':
                fileName = 'main';
                fileExtension = '.py';
                mimeType = 'text/x-python';
                break;
            default:
                // If language cannot be determined from <span>, fallback to provided language
                switch (language.toLowerCase()) {
                    case 'javascript':
                    case 'js':
                        fileName = 'script';
                        fileExtension = '.js';
                        mimeType = 'application/javascript';
                        break;
                    case 'html':
                        fileName = 'index';
                        fileExtension = '.html';
                        mimeType = 'text/html';
                        break;
                    case 'css':
                        fileName = 'styles';
                        fileExtension = '.css';
                        mimeType = 'text/css';
                        break;
                    case 'python':
                    case 'py':
                        fileName = 'main';
                        fileExtension = '.py';
                        mimeType = 'text/x-python';
                        break;
                    case 'java':
                        fileName = 'Main';
                        fileExtension = '.java';
                        mimeType = 'text/x-java-source';
                        break;
                    case 'kotlin':
                        fileName = 'Main';
                        fileExtension = '.kt';
                        mimeType = 'text/x-kotlin';
                        break;
                    case 'c++':
                    case 'cpp':
                        fileName = 'main';
                        fileExtension = '.cpp';
                        mimeType = 'text/x-c++src';
                        break;
                    case 'c#':
                    case 'csharp':
                        fileName = 'Program';
                        fileExtension = '.cs';
                        mimeType = 'text/x-csharp';
                        break;
                    case 'c':
                        fileName = 'main';
                        fileExtension = '.c';
                        mimeType = 'text/x-csrc';
                        break;
                    case 'ruby':
                        fileName = 'script';
                        fileExtension = '.rb';
                        mimeType = 'text/x-ruby';
                        break;
                    case 'rust':
                        fileName = 'main';
                        fileExtension = '.rs';
                        mimeType = 'text/x-rustsrc';
                        break;
                    case 'php':
                        fileName = 'script';
                        fileExtension = '.php';
                        mimeType = 'text/x-php';
                        break;
                    case 'swift':
                        fileName = 'main';
                        fileExtension = '.swift';
                        mimeType = 'text/x-swift';
                        break;
                    case 'typescript':
                    case 'ts':
                        fileName = 'script';
                        fileExtension = '.ts';
                        mimeType = 'application/typescript';
                        break;
                    case 'go':
                        fileName = 'main';
                        fileExtension = '.go';
                        mimeType = 'text/x-go';
                        break;
                    case 'perl':
                        fileName = 'script';
                        fileExtension = '.pl';
                        mimeType = 'text/x-perl';
                        break;
                    case 'lua':
                        fileName = 'script';
                        fileExtension = '.lua';
                        mimeType = 'text/x-lua';
                        break;
                    default:
                        fileName = 'code';
                        fileExtension = '.txt';
                        mimeType = 'text/plain';
                        break;
                }
                break;
        }

        // Create a Blob object with the code content
        const blob = new Blob([codeBlock.innerText], { type: mimeType });

        try {
            if (window.showSaveFilePicker) {
                // Use File System Access API if available
                const fileHandle = await window.showSaveFilePicker({
                    suggestedName: fileName + fileExtension,
                    types: [
                        {
                            description: language,
                            accept: {
                                [mimeType]: [fileExtension],
                            },
                        },
                    ],
                });

                const writable = await fileHandle.createWritable();
                await writable.write(blob);
                await writable.close();
            } else {
                // Fallback for browsers that do not support showSaveFilePicker
                const downloadLink = document.createElement('a');
                downloadLink.href = URL.createObjectURL(blob);
                downloadLink.download = fileName + fileExtension;
                downloadLink.style.display = 'none';
                document.body.appendChild(downloadLink);
                downloadLink.click();
                URL.revokeObjectURL(downloadLink.href);
                document.body.removeChild(downloadLink);
            }
        } catch (error) {
            console.error('Save file dialog was canceled or failed', error);
        }
    }

    // Observe the document for changes and add "Export" button to new code headers
    const observer = new MutationObserver(addExportButtonToHeaders);
    observer.observe(document.body, { childList: true, subtree: true });

    // Initial processing of existing code headers
    addExportButtonToHeaders();

    // Add custom CSS styles if needed
})();

QingJ © 2025

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