您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在 LMArena.ai 页面为代码块添加下载按钮。通用修复版,兼容所有脚本管理器。
// ==UserScript== // @name LMArena Code Downloader (Universal Fix) // @name:zh-CN 大模型竞技场代码下载器 (通用修复版) // @namespace http://tampermonkey.net/ // @version 2.1 // @description Adds a download button to code blocks on lmarena.ai. Universal fix for all script managers. // @description:zh-CN 在 LMArena.ai 页面为代码块添加下载按钮。通用修复版,兼容所有脚本管理器。 // @author AI & Human // @match https://lmarena.ai/* // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWRvd25sb2FkIj48cGF0aCBkPSJNMjEgMTV2NGEyIDIgMCAwIDEtMiAySDVhMiAyIDAgMCAxLTItMlYxNSIvPjxwYXRoIGQ9Im03IDEwIDEgNSA1LTUtNSIvPjxwYXRoIGQ9Ik0xMiAxNVY0Ii8+PC9zdmc+ // @grant none // ==/UserScript== (function() { 'use strict'; // --- 辅助函数 --- /** * 向页面添加全局CSS样式,替代GM_addStyle,兼容所有环境。 * @param {string} css - 要添加的CSS规则字符串。 */ function addGlobalStyle(css) { const head = document.head || document.getElementsByTagName('head')[0]; if (!head) { return; } const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); } function getFileExtension(preElement) { const codeElement = preElement.querySelector('code'); if (!codeElement) return 'txt'; const className = codeElement.className || ''; const match = className.match(/language-(\w+)/); if (match && match[1]) { const langMap = { python: 'py', javascript: 'js', typescript: 'ts', html: 'html', css: 'css', java: 'java', csharp: 'cs', cpp: 'cpp', c: 'c', bash: 'sh', shell: 'sh', json: 'json', markdown: 'md', go: 'go', rust: 'rs', sql: 'sql', yaml: 'yml', xml: 'xml', }; return langMap[match[1].toLowerCase()] || match[1]; } return 'txt'; } function getModelName(preElement) { const messageContainer = preElement.closest('div.flex.gap-6'); if (messageContainer) { const modelNameElement = messageContainer.querySelector('p.font-mono'); if (modelNameElement) { return modelNameElement.textContent.trim().replace(/[^a-zA-Z0-9-.]/g, '_'); } } return 'unknown-model'; } function downloadCode(codeContent, filename) { const blob = new Blob([codeContent], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } // --- 核心逻辑 --- function addDownloadButtons() { // 使用更精确的选择器,专门针对聊天内容区的代码块 const codeBlocks = document.querySelectorAll('main ol div.prose pre:not([data-download-button-added])'); if (codeBlocks.length > 0) { console.log(`[LMArena Downloader] Found ${codeBlocks.length} new code blocks to process.`); } codeBlocks.forEach(pre => { pre.setAttribute('data-download-button-added', 'true'); // 按钮将被添加到<pre>标签内的相对定位的div中 const relativeContainer = pre.querySelector('div.relative'); if (!relativeContainer) { console.error('[LMArena Downloader] Could not find relative container for a code block.'); return; } // 找到原生的复制按钮,我们的按钮会放在它旁边 const nativeCopyButton = relativeContainer.querySelector('button[data-sentry-component="CopyButton"]'); if (!nativeCopyButton) { console.warn('[LMArena Downloader] Could not find the native copy button. The download button will be appended at the end.'); } const downloadButton = document.createElement('button'); downloadButton.className = 'code-downloader-button'; downloadButton.title = 'Download code'; downloadButton.innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V15"/> <polyline points="7 10 12 15 17 10"/> <line x1="12" y1="15" x2="12" y2="3"/> </svg> `; downloadButton.addEventListener('click', (e) => { e.stopPropagation(); const codeElement = pre.querySelector('code'); const codeContent = codeElement ? (codeElement.textContent || '') : ''; const extension = getFileExtension(pre); const modelName = getModelName(pre); const filename = `${modelName}-${Date.now()}.${extension}`; downloadCode(codeContent, filename); }); // 如果找到了复制按钮,就把下载按钮插在它前面,否则就添加到容器末尾 if (nativeCopyButton) { nativeCopyButton.parentElement.insertBefore(downloadButton, nativeCopyButton); } else { relativeContainer.appendChild(downloadButton); } }); } // --- 启动与监听 --- // 1. 先注入样式 addGlobalStyle(` .code-downloader-button { display: inline-flex; align-items: center; justify-content: center; padding: 6px; border-radius: 6px; cursor: pointer; color: var(--interactive-active); transition: background-color 0.2s, color 0.2s; border: none; background-color: transparent; } .code-downloader-button:hover { background-color: var(--surface-hover, #f0f0f0); color: var(--text-primary, #000); } .code-downloader-button svg { width: 18px; height: 18px; } `); // 2. 使用 MutationObserver 监听 DOM 变化 const observer = new MutationObserver((mutations) => { if (mutations.some(m => m.addedNodes.length > 0)) { setTimeout(addDownloadButtons, 300); } }); // 3. 等待核心聊天区域出现后,再开始执行和监听 const startupInterval = setInterval(() => { const chatArea = document.querySelector('main ol'); if (chatArea) { console.log('[LMArena Downloader] Chat area found. Initializing script.'); clearInterval(startupInterval); addDownloadButtons(); // 立即执行一次 observer.observe(document.body, { childList: true, subtree: true }); } }, 500); })();