CodeDown

Adds download buttons to code fields in ChatGPT, Z.Ai, Gemini, LMArena, Kimi, Le Chat, Meta AI, Copilot, Grok, and LongCat, downloading the formatted file ready for use

ติดตั้งสคริปต์นี้?
สคริปต์ที่แนะนำของผู้เขียน

คุณอาจชื่นชอบ My Prompt

ติดตั้งสคริปต์นี้
// ==UserScript==
// @name               CodeDown
// @name:pt-BR         CodeDown
// @name:es            CodeDown
// @name:en            CodeDown
// @name:zh-CN         CodeDown
// @namespace          https://github.com/0H4S
// @version            1.2
// @description        Adds download buttons to code fields in ChatGPT, Z.Ai, Gemini, LMArena, Kimi, Le Chat, Meta AI, Copilot, Grok, and LongCat, downloading the formatted file ready for use
// @description:pt-BR  Adiciona botões de download nos campos de código do ChatGPT, Z.Ai, Gemini, LMArena, Kimi, Le Chat, Meta AI, Copilot, Grok e LongCat, baixando o arquivo formatado pronto para uso.
// @description:en     Adds download buttons to code fields in ChatGPT, Z.Ai, Gemini, LMArena, Kimi, Le Chat, Meta AI, Copilot, Grok, and LongCat, downloading the formatted file ready for use
// @description:es     Añade botones de descarga en los campos de código de ChatGPT, Z.Ai, Gemini, LMArena, Kimi, Le Chat, Meta AI, Copilot, Grok y LongCat, descargando el archivo formateado listo para usar.
// @description:zh-CN  在ChatGPT、Z.Ai、Gemini、LMArena、Kimi、Le Chat、Meta AI、Copilot、Grok和LongCat的代码字段中添加下载按钮,下载格式化的文件以供使用。
// @author             OHAS
// @license            CC-BY-NC-ND-4.0
// @copyright          2025 OHAS. All Rights Reserved.
// @icon               https://cdn-icons-png.flaticon.com/512/8832/8832243.png
// @match              https://chatgpt.com/*
// @match              https://chat.z.ai/*
// @match              https://gemini.google.com/*
// @match              https://lmarena.ai/*
// @match              https://www.kimi.com/*
// @match              https://chat.mistral.ai/*
// @match              https://www.meta.ai/*
// @match              https://copilot.microsoft.com/*
// @match              https://grok.com/*
// @match              https://longcat.chat/*
// @require            https://update.greasyfork.org/scripts/549920/Script%20Notifier.js
// @connect            gist.githubusercontent.com
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_registerMenuCommand
// @grant              GM_xmlhttpRequest
// @grant              GM_addStyle
// @compatible         chrome
// @compatible         firefox
// @compatible         edge
// ==/UserScript==

(function() {
    'use strict';
    if (window.top !== window.self) {
        return;
    }
    const SCRIPT_CONFIG = {
        notificationsUrl: 'https://gist.githubusercontent.com/0H4S/c89814228f65f9a48a26a8919cd13419/raw/codedown.notifications.json',
        scriptVersion: '1.2',
    };
    const notifier = new ScriptNotifier(SCRIPT_CONFIG);
    notifier.run();
    const translations = {
        'pt-br': {
            download: 'Baixar',
            downloadCode: 'Baixar código'
        },
        en: {
            download: 'Download',
            downloadCode: 'Download code'
        },
        es: {
            download: 'Descargar',
            downloadCode: 'Descargar código'
        },
        'zh-cn': {
            download: '下载',
            downloadCode: '下载代码'
        }
    };
    function getLanguage() {
        const lang = (navigator.language || navigator.userLanguage).toLowerCase().split('-')[0];
        switch (lang) {
            case 'pt':
                return 'pt-br';
            case 'es':
                return 'es';
            case 'zh':
                return 'zh-cn';
            case 'en':
                return 'en';
            default:
                return 'en';
        }
    }
    const langKey = getLanguage();
    const i18n = translations[langKey];
    const fileTypeExtensions = {
        javascript: 'js',
        typescript: 'ts',
        html: 'html',
        css: 'css',
        json: 'json',
        python: 'py',
        java: 'java',
        c: 'c',
        cpp: 'cpp',
        'c++': 'cpp',
        'c#': 'cs',
        php: 'php',
        ruby: 'rb',
        go: 'go',
        rust: 'rs',
        swift: 'swift',
        kotlin: 'kt',
        scala: 'scala',
        shell: 'sh',
        bash: 'sh',
        sql: 'sql',
        markdown: 'md',
        yaml: 'yaml',
        xml: 'xml',
        text: 'txt',
        plain: 'txt',
        txt: 'txt'
    };
    function getMimeType(ext) {
        const mime = {
            js: 'application/javascript',
            ts: 'application/typescript',
            html: 'text/html',
            css: 'text/css',
            json: 'application/json',
            py: 'text/x-python',
            java: 'text/x-java-source',
            c: 'text/x-csrc',
            cpp: 'text/x-c++src',
            cs: 'text/x-csharp',
            php: 'application/x-php',
            rb: 'application/x-ruby',
            go: 'text/x-go',
            rs: 'text/x-rust',
            swift: 'text/x-swift',
            kt: 'text/x-kotlin',
            scala: 'text/x-scala',
            sh: 'application/x-sh',
            sql: 'application/sql',
            md: 'text/markdown',
            yaml: 'application/x-yaml',
            xml: 'application/xml',
            txt: 'text/plain'
        };
        return mime[ext] || 'text/plain';
    }
    const isGPT = /chatgpt\.com/.test(location.hostname);
    const isZAI = /chat\.z\.ai/.test(location.hostname);
    const isGemini = /gemini\.google\.com/.test(location.hostname);
    const isLmArena = /lmarena\.ai/.test(location.hostname);
    const isKimi = /kimi\.com/.test(location.hostname);
    const isMistral = /chat\.mistral\.ai/.test(location.hostname);
    const isMetaAI = /meta\.ai/.test(location.hostname);
    const isCopilot = /copilot\.microsoft.com/.test(location.hostname);
    const isGrok = /grok\.com/.test(location.hostname);
    const isLongCat = /longcat\.chat/.test(location.hostname);
    function createAndTriggerDownload(fileName, content, mimeType) {
        const blob = new Blob([content], {
            type: mimeType
        });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileName;
        document.body.appendChild(a);
        a.click();
        setTimeout(() => {
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }, 100);
    }
    // -----------------------
    // --- Sessão GPT ---
    // -----------------------
    if (isGPT) {
        function createDownloadButtonGPT(container) {
            if (container.querySelector('.download-button-gpt')) {
                return;
            }
            const btn = document.createElement('button');
            btn.className = 'flex gap-1 items-center select-none py-1 download-button-gpt';
            btn.setAttribute('aria-label', i18n.downloadCode);
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '20');
            svg.setAttribute('height', '20');
            svg.setAttribute('viewBox', '0 0 20 20');
            svg.setAttribute('fill', 'currentColor');
            svg.classList.add('icon-sm');
            svg.innerHTML = '<path d="M14.707 7.293a1 1 0 0 0-1.414 0L11 9.586V3a1 1 0 1 0-2 0v6.586L6.707 7.293a1 1 0 0 0-1.414 1.414l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414zM3 12a1 1 0 0 1 1 1v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-3a1 1 0 1 1 2 0v3a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3v-3a1 1 0 0 1 1-1z"/>';
            btn.appendChild(svg);
            btn.appendChild(document.createTextNode(i18n.download));
            btn.addEventListener('click', downloadCodeGPT);
            container.insertBefore(btn, container.firstChild);
        }
        function downloadCodeGPT() {
            const block = this.closest('.contain-inline-size');
            if (!block) return;
            const typeEl = block.querySelector('.flex.items-center.text-token-text-secondary');
            const fileType = typeEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = block.querySelector('code');
            if (!codeEl) return;
            const fileName = `CodeDown-ChatGPT-${fileType}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.textContent, getMimeType(ext));
        }
        const checkGPT = () => document.querySelectorAll('.bg-token-bg-elevated-secondary.text-token-text-secondary.flex').forEach(createDownloadButtonGPT);
        setInterval(checkGPT, 1000);
        window.addEventListener('load', checkGPT);
    }
    // -----------------------
    // --- Sessão Z AI ---
    // -----------------------
    if (isZAI) {
        function createDownloadButtonZAI(copyBtn) {
            const buttonContainer = copyBtn.parentElement;
            if (!buttonContainer || buttonContainer.querySelector('.download-button-zai')) {
                return;
            }
            const btn = document.createElement('button');
            btn.className = `${copyBtn.className} download-button-zai`;
            btn.setAttribute('aria-label', i18n.downloadCode);
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '20');
            svg.setAttribute('height', '20');
            svg.setAttribute('viewBox', '0 0 20 20');
            svg.setAttribute('fill', 'currentColor');
            svg.classList.add('size-3');
            svg.innerHTML = '<path d="M14.707 7.293a1 1 0 0 0-1.414 0L11 9.586V3a1 1 0 1 0-2 0v6.586L6.707 7.293a1 1 0 0 0-1.414 1.414l4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414zM3 12a1 1 0 0 1 1 1v3a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-3a1 1 0 1 1 2 0v3a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3v-3a1 1 0 0 1 1-1z"/>';
            btn.appendChild(svg);
            btn.appendChild(document.createTextNode(i18n.download));
            btn.addEventListener('click', downloadCodeZAI);
            buttonContainer.insertBefore(btn, copyBtn);
        }
        function downloadCodeZAI() {
            const root = this.closest('.relative');
            if (!root) return;
            const contentEl = root.querySelector('.cm-content[data-language]');
            if (!contentEl) return;
            const lang = (contentEl.getAttribute('data-language') || 'txt').toLowerCase();
            const ext = fileTypeExtensions[lang] || 'txt';
            const text = Array.from(contentEl.querySelectorAll('.cm-line')).map(div => div.innerText.replace(/\u00a0/g, ' ')).join('\n');
            const fileName = `CodeDown-Z.ai-${lang}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, text, getMimeType(ext));
        }
        const checkZAI = () => {
            document.querySelectorAll('button svg path[d^="M853.333333 298.666667"]').forEach(path => {
                const copyBtn = path.closest('button');
                if (copyBtn) createDownloadButtonZAI(copyBtn);
            });
        };
        setInterval(checkZAI, 1000);
        window.addEventListener('load', checkZAI);
    }
    // -----------------------
    // --- Sessão Gemini ---
    // -----------------------
    if (isGemini) {
        GM_addStyle(`#codedown-gemini-tooltip { position: fixed; background: white; color: black; padding: 6px 10px; border-radius: 6px; font-size: 13px; font-family: sans-serif; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.2s, visibility 0.2s; z-index: 2147483647; box-shadow: 0 2px 5px rgba(0,0,0,0.2); }`);
        let tooltip = document.createElement('div');
        tooltip.id = 'codedown-gemini-tooltip';
        document.body.appendChild(tooltip);
        function createDownloadButtonGemini(copyBtn) {
            if (copyBtn.parentElement.querySelector('.download-button-gemini')) return;
            const btn = document.createElement('button');
            btn.className = copyBtn.className + ' download-button-gemini';
            btn.setAttribute('aria-label', i18n.downloadCode);
            const matIcon = document.createElement('mat-icon');
            matIcon.className = copyBtn.querySelector('mat-icon').className;
            matIcon.setAttribute('role', 'img');
            matIcon.setAttribute('aria-hidden', 'true');
            matIcon.textContent = 'download';
            btn.appendChild(matIcon);
            btn.addEventListener('click', downloadCodeGemini);
            btn.addEventListener('mouseover', (e) => {
                const rect = e.currentTarget.getBoundingClientRect();
                tooltip.textContent = i18n.downloadCode;
                tooltip.style.opacity = '1';
                tooltip.style.visibility = 'visible';
                tooltip.style.top = `${rect.bottom + 8}px`;
                tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`;
            });
            btn.addEventListener('mouseout', () => {
                tooltip.style.opacity = '0';
                tooltip.style.visibility = 'hidden';
            });
            copyBtn.parentElement.insertBefore(btn, copyBtn);
        }
        function downloadCodeGemini(event) {
            const header = event.currentTarget.closest('.buttons').parentElement;
            const spanType = header.querySelector('span');
            const fileType = spanType?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = event.currentTarget.closest('code-block').querySelector('code[data-test-id="code-content"]');
            if (!codeEl) return;
            const fileName = `CodeDown-Gemini-${fileType}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkGemini = () => document.querySelectorAll('button.copy-button').forEach(createDownloadButtonGemini);
        setInterval(checkGemini, 1000);
        window.addEventListener('load', checkGemini);
    }
    // -----------------------
    // --- Sessão LMArena ---
    // -----------------------
    if (isLmArena) {
        GM_addStyle(`.download-button-lmarena { position: relative; } .download-button-lmarena::before { content: attr(data-tooltip); position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 8px; background-color: white; color: black; padding: 5px 9px; border-radius: 5px; font-size: 13px; white-space: nowrap; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.2s, visibility 0.2s; z-index: 2147483647; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } .download-button-lmarena:hover::before { opacity: 1; visibility: visible; }`);
        function createDownloadButtonLmArena(copyBtn) {
            if (copyBtn.parentElement.classList.contains('code-down-buttons-wrapper')) return;
            const wrapper = document.createElement('div');
            wrapper.className = 'flex items-center gap-2 code-down-buttons-wrapper';
            const btn = document.createElement('button');
            btn.className = copyBtn.className + ' download-button-lmarena';
            btn.setAttribute('aria-label', i18n.downloadCode);
            btn.setAttribute('type', 'button');
            btn.setAttribute('data-tooltip', i18n.downloadCode);
            const downloadSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            downloadSvg.setAttribute('width', '16');
            downloadSvg.setAttribute('height', '16');
            downloadSvg.setAttribute('viewBox', '0 0 24 24');
            downloadSvg.setAttribute('fill', 'none');
            downloadSvg.setAttribute('stroke', 'currentColor');
            downloadSvg.setAttribute('stroke-width', '2');
            downloadSvg.setAttribute('stroke-linecap', 'round');
            downloadSvg.setAttribute('stroke-linejoin', 'round');
            downloadSvg.innerHTML = '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>';
            btn.appendChild(downloadSvg);
            btn.addEventListener('click', downloadCodeLmArena);
            copyBtn.parentElement.insertBefore(wrapper, copyBtn);
            wrapper.appendChild(btn);
            wrapper.appendChild(copyBtn);
        }
        function downloadCodeLmArena(event) {
            event.stopPropagation();
            const container = this.closest('[data-sentry-component="CodeBlock"]');
            if (!container) return;
            const langEl = container.querySelector('[data-sentry-component="CodeBlockGroup"] span');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = container.querySelector('[data-sentry-element="CodeBlockCode"] code');
            if (!codeEl) return;
            const fileName = `CodeDown-LMArena-${fileType}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkLmArena = () => document.querySelectorAll('[data-sentry-component="CodeBlock"] button[data-sentry-component="CopyButton"]').forEach(createDownloadButtonLmArena);
        setInterval(checkLmArena, 1000);
        window.addEventListener('load', checkLmArena);
    }
    // -----------------------
    // --- Sessão Kimi ---
    // -----------------------
    if (isKimi) {
        function createDownloadButtonKimi(copyBtn) {
            const headerContent = copyBtn.parentElement;
            if (!headerContent || headerContent.querySelector('.download-button-kimi')) return;
            const btn = copyBtn.cloneNode(true);
            btn.classList.add('download-button-kimi');
            btn.querySelector('span').textContent = i18n.download;
            const svg = btn.querySelector('svg');
            svg.setAttribute('viewBox', '0 0 24 24');
            svg.innerHTML = '<path d="M5 20h14v-2H5v2zm14-9h-4V3H9v8H5l7 7l7-7z" fill="currentColor"></path>';
            btn.addEventListener('click', downloadCodeKimi);
            if (!copyBtn.parentElement.classList.contains('codedown-wrapper')) {
                const wrapper = document.createElement('div');
                wrapper.className = 'codedown-wrapper';
                wrapper.style.display = 'flex';
                wrapper.style.gap = '8px';
                headerContent.replaceChild(wrapper, copyBtn);
                wrapper.appendChild(btn);
                wrapper.appendChild(copyBtn);
            }
        }
        function downloadCodeKimi() {
            const codeBlock = this.closest('.segment-code');
            if (!codeBlock) return;
            const langEl = codeBlock.querySelector('.segment-code-lang');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = codeBlock.querySelector('code');
            if (!codeEl) return;
            const fileName = `CodeDown-Kimi-${fileType}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkKimi = () => document.querySelectorAll('.segment-code-header-content .simple-button').forEach(createDownloadButtonKimi);
        setInterval(checkKimi, 1000);
        window.addEventListener('load', checkKimi);
    }
    // -----------------------
    // --- Sessão Le Chat (Mistral) ---
    // -----------------------
    if (isMistral) {
        function createDownloadButtonMistral(copyBtn) {
            const parent = copyBtn.parentElement;
            if (parent.querySelector('.download-button-mistral')) {
                return;
            }
            const btn = document.createElement('button');
            btn.className = copyBtn.className + ' download-button-mistral';
            btn.setAttribute('type', 'button');
            btn.setAttribute('aria-label', i18n.downloadCode);
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            for (const attr of copyBtn.querySelector('svg').attributes) {
                svg.setAttribute(attr.name, attr.value);
            }
            svg.innerHTML = '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>';
            btn.appendChild(svg);
            btn.appendChild(document.createTextNode(i18n.download));
            btn.addEventListener('click', downloadCodeMistral);
            parent.insertBefore(btn, copyBtn);
        }
        function downloadCodeMistral() {
            const container = this.closest('.relative.rounded-md');
            if (!container) return;
            const codeEl = container.querySelector('code[class*="language-"]');
            if (!codeEl) return;
            const langMatch = Array.from(codeEl.classList).find(c => c.startsWith('language-'));
            const fileType = langMatch ? langMatch.replace('language-', '').toLowerCase() : 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const fileName = `CodeDown-LeChat-${fileType}-${new Date().toISOString().replace(/[:.]/g,'-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkMistral = () => {
            document.querySelectorAll('div[data-exclude-copy="true"] button svg.lucide-copy').forEach(svgEl => {
                const copyBtn = svgEl.closest('button');
                if (copyBtn) {
                    createDownloadButtonMistral(copyBtn);
                }
            });
        };
        setInterval(checkMistral, 1000);
        window.addEventListener('load', checkMistral);
    }
    // -----------------------
    // --- Sessão Meta AI ---
    // -----------------------
    if (isMetaAI) {
        function createDownloadButtonMetaAI(copyBtn) {
            const parent = copyBtn.parentElement;
            if (!parent || parent.querySelector('.download-button-meta')) {
                return;
            }
            const btn = copyBtn.cloneNode(true);
            btn.classList.add('download-button-meta');
            btn.setAttribute('aria-label', i18n.download);
            btn.removeAttribute('data-tooltip-content');
            const svg = btn.querySelector('svg');
            if (svg) {
                svg.innerHTML = '<path fill-rule="evenodd" clip-rule="evenodd" d="M5 20h14v-2H5v2zM19 9h-4V3H9v6H5l7 7 7-7z"></path>';
            }
            btn.addEventListener('click', downloadCodeMetaAI);
            parent.insertBefore(btn, copyBtn);
        }
        function downloadCodeMetaAI(event) {
            event.stopPropagation();
            const container = this.closest('.x78zum5.xdt5ytf.xfe5zq5');
            if (!container) return;
            const langEl = container.querySelector('div[class*="x6s0dn4"] > span');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = container.querySelector('pre > code');
            if (!codeEl) return;
            const fileName = `CodeDown-Meta-${fileType}-${new Date().toISOString().replace(/[:.]/g, '-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkMetaAI = () => {
            const svgPathSelector = 'M5 14h1v2H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v1h-2V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1zm14 6h-8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1zm3-1a3 3 0 0 1-3 3h-8a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v8z';
            document.querySelectorAll(`svg path[d="${svgPathSelector}"]`).forEach(pathEl => {
                const copyBtn = pathEl.closest('div[role="button"]');
                if (copyBtn) {
                    const container = copyBtn.closest('.x78zum5.xdt5ytf.xfe5zq5');
                    if (container && container.querySelector('pre > code')) {
                        createDownloadButtonMetaAI(copyBtn);
                    }
                }
            });
        };
        setInterval(checkMetaAI, 1000);
        window.addEventListener('load', checkMetaAI);
    }
    // -----------------------
    // --- Sessão Copilot ---
    // -----------------------
    if (isCopilot) {
        function createDownloadButtonCopilot(copyBtn) {
            const parent = copyBtn.parentElement;
            if (parent.querySelector('.download-button-copilot')) {
                return;
            }
            const btn = copyBtn.cloneNode(true);
            btn.classList.add('download-button-copilot');
            btn.setAttribute('title', i18n.downloadCode);
            btn.removeAttribute('data-copy');
            const contentDiv = btn.querySelector('div');
            if (contentDiv) {
                contentDiv.innerHTML = `<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-5"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 19v-2h14v2H5z"></path></svg> ${i18n.download}`;
            }
            btn.addEventListener('click', downloadCodeCopilot);
            const wrapper = document.createElement('div');
            wrapper.className = 'flex items-center codedown-copilot-wrapper';
            wrapper.style.gap = '0.25rem';
            parent.insertBefore(wrapper, copyBtn);
            wrapper.appendChild(btn);
            wrapper.appendChild(copyBtn);
        }
        function downloadCodeCopilot(event) {
            event.stopPropagation();
            const header = this.closest('.flex.justify-between.items-center');
            const container = header ? header.parentElement : null;
            if (!container) return;
            const langEl = container.querySelector('.capitalize');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = container.querySelector('pre > code');
            if (!codeEl) return;
            const fileName = `CodeDown-Copilot-${fileType}-${new Date().toISOString().replace(/[:.]/g, '-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkCopilot = () => {
            const svgPathSelector = 'M8.5 2C7.39543 2 6.5 2.89543 6.5 4V14C6.5 15.1046 7.39543 16 8.5 16H14.5C15.6046 16 16.5 15.1046 16.5 14V4C16.5 2.89543 15.6046 2 14.5 2H8.5ZM7.5 4C7.5 3.44772 7.94772 3 8.5 3H14.5C15.0523 3 15.5 3.44772 15.5 4V14C15.5 14.5523 15.0523 15 14.5 15H8.5C7.94772 15 7.5 14.5523 7.5 14V4ZM4.5 6.00001C4.5 5.25973 4.9022 4.61339 5.5 4.26758V14.5C5.5 15.8807 6.61929 17 8 17H14.2324C13.8866 17.5978 13.2403 18 12.5 18H8C6.067 18 4.5 16.433 4.5 14.5V6.00001Z';
            document.querySelectorAll(`button svg mask path[d="${svgPathSelector}"]`).forEach(pathEl => {
                const copyBtn = pathEl.closest('button');
                if (copyBtn && !copyBtn.parentElement.classList.contains('codedown-copilot-wrapper')) {
                    createDownloadButtonCopilot(copyBtn);
                }
            });
        };
        setInterval(checkCopilot, 1000);
        window.addEventListener('load', checkCopilot);
    }
    // -----------------------
    // --- Sessão Grok ---
    // -----------------------
    if (isGrok) {
        function createDownloadButtonGrok(collapseBtn) {
            const parent = collapseBtn.parentElement;
            if (parent.querySelector('.download-button-grok')) return;
            const btn = collapseBtn.cloneNode(true);
            btn.classList.add('download-button-grok');
            btn.setAttribute('aria-label', i18n.downloadCode);
            const svg = btn.querySelector('svg');
            if (svg) {
                svg.innerHTML = '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>';
                svg.setAttribute('viewBox', '0 0 24 24');
            }
            const span = btn.querySelector('span');
            if (span) {
                span.textContent = i18n.download;
            }
            btn.addEventListener('click', downloadCodeGrok);
            parent.insertBefore(btn, collapseBtn);
        }
        function downloadCodeGrok(event) {
            event.stopPropagation();
            const container = this.closest('.relative.not-prose');
            if (!container) return;
            const langEl = container.querySelector('.flex.flex-row.px-4 span');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = container.querySelector('pre.shiki > code');
            if (!codeEl) return;
            const codeText = Array.from(codeEl.querySelectorAll('.line'))
                                .map(line => line.textContent)
                                .join('\n');
            const fileName = `CodeDown-Grok-${fileType}-${new Date().toISOString().replace(/[:.]/g, '-')}.${ext}`;
            createAndTriggerDownload(fileName, codeText, getMimeType(ext));
        }
        const checkGrok = () => {
            document.querySelectorAll('button svg.lucide-chevrons-down-up').forEach(svgEl => {
                const collapseBtn = svgEl.closest('button');
                if (collapseBtn) {
                    createDownloadButtonGrok(collapseBtn);
                }
            });
        };
        setInterval(checkGrok, 1000);
        window.addEventListener('load', checkGrok);
    }
    // -----------------------
    // --- Sessão LongCat ---
    // -----------------------
    if (isLongCat) {
        function createDownloadButtonLongCat(copyBtn) {
            if (copyBtn.parentElement.classList.contains('codedown-longcat-wrapper')) {
                return;
            }
            const header = copyBtn.parentElement;
            if (header.querySelector('.download-button-longcat')) {
                return;
            }
            const btn = document.createElement('div');
            btn.className = copyBtn.className + ' download-button-longcat';
            btn.setAttribute('aria-label', i18n.downloadCode);
            btn.style.display = 'flex';
            btn.style.alignItems = 'center';
            btn.style.gap = '5px';
            const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('width', '16');
            svg.setAttribute('height', '16');
            svg.setAttribute('viewBox', '0 0 24 24');
            svg.setAttribute('fill', 'none');
            svg.setAttribute('stroke', 'currentColor');
            svg.setAttribute('stroke-width', '2');
            svg.setAttribute('stroke-linecap', 'round');
            svg.setAttribute('stroke-linejoin', 'round');
            svg.innerHTML = '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line>';
            const span = document.createElement('span');
            span.className = 'code-block-header__text code-block-header__click';
            span.textContent = i18n.download;
            btn.appendChild(svg);
            btn.appendChild(span);
            btn.addEventListener('click', downloadCodeLongCat);
            const wrapper = document.createElement('div');
            wrapper.className = 'codedown-longcat-wrapper';
            wrapper.style.display = 'flex';
            wrapper.style.alignItems = 'center';
            wrapper.style.gap = '12px';
            header.insertBefore(wrapper, copyBtn);
            wrapper.appendChild(btn);
            wrapper.appendChild(copyBtn);
        }
        function downloadCodeLongCat(event) {
            event.stopPropagation();
            const header = this.closest('.code-block-header');
            if (!header) return;
            const codeBlockContainer = header.parentElement;
            if (!codeBlockContainer) return;
            const langEl = header.querySelector('.code-block-header__lang');
            const fileType = langEl?.textContent.trim().toLowerCase() || 'txt';
            const ext = fileTypeExtensions[fileType] || 'txt';
            const codeEl = codeBlockContainer.querySelector('code.code-block-body');
            if (!codeEl) return;
            const fileName = `CodeDown-LongCat-${fileType}-${new Date().toISOString().replace(/[:.]/g, '-')}.${ext}`;
            createAndTriggerDownload(fileName, codeEl.innerText, getMimeType(ext));
        }
        const checkLongCat = () => {
            document.querySelectorAll('.code-block-header__copy').forEach(createDownloadButtonLongCat);
        };
        setInterval(checkLongCat, 1000);
        window.addEventListener('load', checkLongCat);
    }
})();