// ==UserScript== // @name 导出DeepSeek回答为图片 | Export DeepSeek Answer to Image // @namespace http://github.com/byronleeeee/exportDeepseek // @version 1.2 // @description 将DeepSeek的回答导出为一张图片,支持选择多个聊天内容和添加用户头像 // @author ByronLeeeee // @match *://chat.deepseek.com/* // @grant none // @require https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/530683/%E5%AF%BC%E5%87%BADeepSeek%E5%9B%9E%E7%AD%94%E4%B8%BA%E5%9B%BE%E7%89%87%20%7C%20Export%20DeepSeek%20Answer%20to%20Image.user.js // @updateURL https://update.greasyfork.icu/scripts/530683/%E5%AF%BC%E5%87%BADeepSeek%E5%9B%9E%E7%AD%94%E4%B8%BA%E5%9B%BE%E7%89%87%20%7C%20Export%20DeepSeek%20Answer%20to%20Image.meta.js // ==/UserScript== (function() { 'use strict'; // i18n translations const i18n = { 'zh': { exportBtn: '导出AI回答为图片', notFound: 'AI回答区域未找到!', selectScheme: '选择配色方案:', footer: '回答来自DeepSeek,仅供参考', lastAnswer: '最新回答', multiSelectMode: '多选模式', exportSelected: '导出选中的对话', selectAll: '全选', deselectAll: '取消全选', userMessage: '用户', aiMessage: 'AI', selectItems: '请选择要导出的对话内容:', noItemsSelected: '请至少选择一个对话内容', colorSchemes: [ { name: '白色-蓝色', top: '#FFFFFF', bottom: '#4D6BFE', textTop: '#000000', textBottom: '#FFFFFF' }, { name: '黑色-金色', top: '#121212', bottom: '#FFD700', textTop: '#FFFFFF', textBottom: '#000000' }, { name: '浅灰-青色', top: '#F5F5F5', bottom: '#008080', textTop: '#000000', textBottom: '#FFFFFF' }, { name: '深灰-紫色', top: '#333333', bottom: '#800080', textTop: '#FFFFFF', textBottom: '#FFFFFF' } ], error: '生成图片失败,请查看控制台了解详情。', cancel: '取消', export: '导出', next: '下一步', back: '返回', addCreator: '添加生成者信息', creatorName: '生成者名称', creatorPlaceholder: '输入你的名字', addAvatar: '添加用户头像' }, 'en': { exportBtn: 'Export AI Answer to Image', notFound: 'AI answer div not found!', selectScheme: 'Select a color scheme:', footer: 'Answer from DeepSeek, for reference only', lastAnswer: 'Last Answer', multiSelectMode: 'Multi-select Mode', exportSelected: 'Export Selected Items', selectAll: 'Select All', deselectAll: 'Deselect All', userMessage: 'User', aiMessage: 'AI', selectItems: 'Please select chat items to export:', noItemsSelected: 'Please select at least one chat item', colorSchemes: [ { name: 'White-Blue', top: '#FFFFFF', bottom: '#4D6BFE', textTop: '#000000', textBottom: '#FFFFFF' }, { name: 'Black-Gold', top: '#121212', bottom: '#FFD700', textTop: '#FFFFFF', textBottom: '#000000' }, { name: 'Light Gray-Teal', top: '#F5F5F5', bottom: '#008080', textTop: '#000000', textBottom: '#FFFFFF' }, { name: 'Dark Gray-Purple', top: '#333333', bottom: '#800080', textTop: '#FFFFFF', textBottom: '#FFFFFF' } ], error: 'Failed to generate image. Check console for details.', cancel: 'Cancel', export: 'Export', next: 'Next', back: 'Back', addCreator: 'Add creator info', creatorName: 'Creator name', creatorPlaceholder: 'Enter your name', addAvatar: 'Add user avatar' } }; const userLang = (navigator.language || navigator.userLanguage).split('-')[0]; const lang = i18n[userLang] ? userLang : 'en'; const texts = i18n[lang]; // Add styles with dark mode support function addStyles() { const style = document.createElement('style'); style.textContent = ` .ai-export-fab { position: fixed; bottom: 24px; right: 24px; width: 56px; height: 56px; border-radius: 50%; background-color: #4D6BFE; color: white; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 8px rgba(0,0,0,0.2); z-index: 9999; transition: all 0.3s ease; } .ai-export-fab:hover { transform: scale(1.05); box-shadow: 0 6px 12px rgba(0,0,0,0.3); } .ai-export-fab-icon { display: flex; align-items: center; justify-content: center; } .ai-export-tooltip { position: absolute; background: rgba(0,0,0,0.7); color: white; padding: 5px 10px; border-radius: 4px; font-size: 12px; white-space: nowrap; right: 70px; opacity: 0; transition: opacity 0.3s; pointer-events: none; } .ai-export-fab:hover .ai-export-tooltip { opacity: 1; } .ai-color-scheme-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 10000; } .ai-modal-content { background-color: white; border-radius: 8px; padding: 20px; width: 400px; max-width: 90%; color: #000000; } body.dark .ai-modal-content { background-color: #1e1e1e; color: #ffffff; } .ai-modal-header { font-size: 18px; font-weight: bold; margin-bottom: 15px; } .ai-scheme-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 15px; } .ai-scheme-option { border: 2px solid transparent; border-radius: 6px; overflow: hidden; cursor: pointer; transition: all 0.2s; } .ai-scheme-option:hover { transform: translateY(-2px); } .ai-scheme-option.selected { border-color: #4D6BFE; } .ai-scheme-preview { display: flex; flex-direction: column; height: 100px; } .ai-scheme-top { flex: 3; display: flex; align-items: center; justify-content: center; font-weight: bold; } .ai-scheme-bottom { flex: 1; display: flex; align-items: center; justify-content: center; font-size: 12px; } .ai-modal-buttons { display: flex; justify-content: flex-end; gap: 10px; } .ai-modal-button { padding: 8px 16px; border-radius: 4px; border: none; cursor: pointer; font-weight: bold; } .ai-modal-button.primary { background-color: #4D6BFE; color: white; } .ai-modal-button.secondary { background-color: #f1f1f1; color: #333; } body.dark .ai-modal-button.secondary { background-color: #333333; color: #ffffff; } .ai-export-button { position: absolute; top: 10px; right: 10px; background-color: #4D6BFE; color: white; border: none; border-radius: 4px; padding: 4px 8px; font-size: 12px; cursor: pointer; opacity: 0; transition: opacity 0.2s; z-index: 100; } ._4f9bf79:hover .ai-export-button, .fbb737a4:hover .ai-export-button { opacity: 1; } .ai-creator-option { margin: 15px 0; } .ai-creator-checkbox { margin-right: 8px; } .ai-creator-input { margin-top: 8px; width: 100%; padding: 8px; border-radius: 4px; border: 1px solid #ccc; box-sizing: border-box; display: none; } body.dark .ai-creator-input { background-color: #333; color: #fff; border-color: #555; } .ai-chat-selection { max-height: 50vh; overflow-y: auto; margin: 15px 0; border: 1px solid #eee; border-radius: 8px; padding: 10px; } body.dark .ai-chat-selection { border-color: #333; } .ai-chat-item { display: flex; align-items: center; padding: 8px; margin: 5px 0; border-radius: 4px; background-color: #f9f9f9; border-left: 4px solid transparent; transition: all 0.2s; } body.dark .ai-chat-item { background-color: #2a2a2a; } .ai-chat-item:hover { background-color: #f1f1f1; } body.dark .ai-chat-item:hover { background-color: #333; } .ai-chat-item.ai { border-left-color: #4D6BFE; } .ai-chat-item.user { border-left-color: #6FCF97; } .ai-chat-checkbox { margin-right: 10px; } .ai-chat-preview { flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 14px; } .ai-chat-type { font-size: 12px; padding: 2px 6px; border-radius: 10px; margin-left: 8px; } .ai-chat-type.ai { background-color: #E1E7FF; color: #4D6BFE; } body.dark .ai-chat-type.ai { background-color: #2a3a70; color: #8aa3ff; } .ai-chat-type.user { background-color: #E3F9EB; color: #6FCF97; } body.dark .ai-chat-type.user { background-color: #2a4a3a; color: #8ae0a9; } .ai-selection-actions { display: flex; justify-content: space-between; margin-bottom: 10px; } .ai-selection-buttons { display: flex; gap: 8px; } .ai-select-button { font-size: 12px; padding: 4px 8px; background-color: #f1f1f1; border: none; border-radius: 4px; cursor: pointer; } body.dark .ai-select-button { background-color: #333; color: #fff; } .ai-select-button:hover { background-color: #e1e1e1; } body.dark .ai-select-button:hover { background-color: #444; } .ai-chat-wrapper { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 15px; padding: 10px; } .ai-chat-content { flex-grow: 1; } .ai-user-avatar { width: 32px; height: 32px; border-radius: 50%; margin-left: 10px; } `; document.head.appendChild(style); } // Create FAB function createFAB() { const fab = document.createElement('div'); fab.innerHTML = `
${texts.multiSelectMode}
`; document.body.appendChild(fab); fab.querySelector('.ai-export-fab').addEventListener('click', () => { showMultiSelectModal(); }); } // Add export buttons to each message function addExportButtonsToMessages() { const observer = new MutationObserver(() => { const aiDivs = document.querySelectorAll('div._4f9bf79._43c05b5'); aiDivs.forEach(aiDiv => { if (!aiDiv.querySelector('.ai-export-button')) { const exportButton = document.createElement('button'); exportButton.className = 'ai-export-button'; exportButton.textContent = texts.exportBtn; exportButton.addEventListener('click', () => { showColorSchemeModal([aiDiv], false); }); const parentDiv = aiDiv.closest('.ds-relative') || aiDiv; parentDiv.style.position = 'relative'; parentDiv.appendChild(exportButton); } }); const userDivs = document.querySelectorAll('div.fbb737a4'); userDivs.forEach(userDiv => { if (!userDiv.querySelector('.ai-export-button')) { const exportButton = document.createElement('button'); exportButton.className = 'ai-export-button'; exportButton.textContent = texts.exportBtn; exportButton.addEventListener('click', () => { showColorSchemeModal([userDiv], false); }); const parentDiv = userDiv.closest('.ds-relative') || userDiv; parentDiv.style.position = 'relative'; parentDiv.appendChild(exportButton); } }); }); observer.observe(document.body, { childList: true, subtree: true }); const aiDivs = document.querySelectorAll('div._4f9bf79._43c05b5'); aiDivs.forEach(aiDiv => { if (!aiDiv.querySelector('.ai-export-button')) { const exportButton = document.createElement('button'); exportButton.className = 'ai-export-button'; exportButton.textContent = texts.exportBtn; exportButton.addEventListener('click', () => { showColorSchemeModal([aiDiv], false); }); const parentDiv = aiDiv.closest('.ds-relative') || aiDiv; parentDiv.style.position = 'relative'; parentDiv.appendChild(exportButton); } }); const userDivs = document.querySelectorAll('div.fbb737a4'); userDivs.forEach(userDiv => { if (!userDiv.querySelector('.ai-export-button')) { const exportButton = document.createElement('button'); exportButton.className = 'ai-export-button'; exportButton.textContent = texts.exportBtn; exportButton.addEventListener('click', () => { showColorSchemeModal([userDiv], false); }); const parentDiv = userDiv.closest('.ds-relative') || userDiv; parentDiv.style.position = 'relative'; parentDiv.appendChild(exportButton); } }); } // Show multi-select modal function showMultiSelectModal() { const aiDivs = Array.from(document.querySelectorAll('div._4f9bf79._43c05b5')); const userDivs = Array.from(document.querySelectorAll('div.fbb737a4')); if (!aiDivs.length && !userDivs.length) { alert(texts.notFound); return; } const allMessages = [...aiDivs, ...userDivs].sort((a, b) => { const position = a.compareDocumentPosition(b); return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1; }); const modal = document.createElement('div'); modal.className = 'ai-color-scheme-modal'; modal.innerHTML = `
${texts.selectItems}
${allMessages.map((div, index) => { const isAI = div.classList.contains('_4f9bf79'); const type = isAI ? 'ai' : 'user'; const label = isAI ? texts.aiMessage : texts.userMessage; let content; if (isAI) { content = div.textContent.trim(); } else { // For user messages, remove ai-export-button and afb1eea3 const tempDiv = div.cloneNode(true); const exportButton = tempDiv.querySelector('.ai-export-button'); if (exportButton) exportButton.remove(); const afb1eea3 = tempDiv.querySelector('.afb1eea3'); if (afb1eea3) afb1eea3.remove(); content = tempDiv.textContent.trim(); } if (content.length > 60) content = content.substring(0, 57) + '...'; return `
${label}
`; }).join('')}
`; document.body.appendChild(modal); modal.querySelector('#ai-select-all').addEventListener('click', () => { modal.querySelectorAll('.ai-chat-checkbox').forEach(checkbox => { checkbox.checked = true; }); }); modal.querySelector('#ai-deselect-all').addEventListener('click', () => { modal.querySelectorAll('.ai-chat-checkbox').forEach(checkbox => { checkbox.checked = false; }); }); modal.querySelector('#ai-cancel-btn').addEventListener('click', () => { document.body.removeChild(modal); }); modal.querySelector('#ai-continue-btn').addEventListener('click', () => { const selectedIndices = []; modal.querySelectorAll('.ai-chat-checkbox').forEach((checkbox, i) => { if (checkbox.checked) { const itemIndex = parseInt(checkbox.closest('.ai-chat-item').dataset.index); selectedIndices.push(itemIndex); } }); if (selectedIndices.length === 0) { alert(texts.noItemsSelected); return; } const selectedDivs = selectedIndices.map(index => allMessages[index]); document.body.removeChild(modal); showColorSchemeModal(selectedDivs, true); }); } // Show color scheme modal function showColorSchemeModal(selectedDivs, isMultiSelect) { const modal = document.createElement('div'); modal.className = 'ai-color-scheme-modal'; let selectedSchemeIndex = 0; let creatorName = ''; let addCreatorInfo = false; let addUserAvatar = false; const profileNameElement = document.querySelector('.ds-dropdown-menu-option__label'); const defaultCreatorName = profileNameElement ? profileNameElement.textContent.trim() : ''; modal.innerHTML = `
${texts.selectScheme}
${texts.colorSchemes.map((scheme, index) => `
AI
DeepSeek
`).join('')}
${isMultiSelect ? `` : ''}
`; document.body.appendChild(modal); const schemeOptions = modal.querySelectorAll('.ai-scheme-option'); schemeOptions.forEach(option => { option.addEventListener('click', () => { schemeOptions.forEach(opt => opt.classList.remove('selected')); option.classList.add('selected'); selectedSchemeIndex = parseInt(option.dataset.index); }); }); const creatorCheckbox = modal.querySelector('.ai-creator-checkbox'); const creatorInput = modal.querySelector('.ai-creator-input'); const avatarCheckbox = modal.querySelector('.ai-avatar-checkbox'); creatorCheckbox.addEventListener('change', () => { addCreatorInfo = creatorCheckbox.checked; creatorInput.disabled = !addCreatorInfo; creatorInput.style.display = addCreatorInfo ? 'block' : 'none'; }); avatarCheckbox.addEventListener('change', () => { addUserAvatar = avatarCheckbox.checked; }); addCreatorInfo = creatorCheckbox.checked; creatorInput.style.display = addCreatorInfo ? 'block' : 'none'; if (isMultiSelect) { modal.querySelector('#ai-back-btn').addEventListener('click', () => { document.body.removeChild(modal); showMultiSelectModal(); }); } modal.querySelector('#ai-cancel-btn').addEventListener('click', () => { document.body.removeChild(modal); }); modal.querySelector('#ai-export-btn').addEventListener('click', async () => { creatorName = creatorInput.value.trim(); document.body.removeChild(modal); await generateAndDownloadImage(selectedDivs, texts.colorSchemes[selectedSchemeIndex], texts, addCreatorInfo, creatorName, addUserAvatar); }); } // Default SVG avatar (centered) const defaultAvatarSVG = ` `; // Generate and download image async function generateAndDownloadImage(selectedDivs, colorScheme, texts, addCreatorInfo, creatorName, addUserAvatar) { const container = document.createElement('div'); container.style.width = '600px'; container.style.borderRadius = '10px'; container.style.overflow = 'hidden'; container.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)'; container.style.display = 'flex'; container.style.flexDirection = 'column'; const topSection = document.createElement('div'); topSection.style.padding = '20px'; topSection.style.backgroundColor = colorScheme.top; topSection.style.color = colorScheme.textTop; // Get user avatar if selected, otherwise use default let userAvatar = null; if (addUserAvatar) { const avatarImg = document.querySelector('img.fdf01f38'); if (avatarImg) { userAvatar = avatarImg.cloneNode(true); userAvatar.className = 'ai-user-avatar'; userAvatar.removeAttribute('aria-hidden'); } } if (!userAvatar) { const avatarContainer = document.createElement('div'); avatarContainer.innerHTML = defaultAvatarSVG; userAvatar = avatarContainer.firstElementChild; } selectedDivs.forEach(div => { const isAI = div.classList.contains('_4f9bf79'); let contentDiv; const chatWrapper = document.createElement('div'); chatWrapper.className = 'ai-chat-wrapper'; if (isAI) { // For AI messages, clone the full div and remove unwanted elements contentDiv = div.cloneNode(true); const buttonDiv = contentDiv.querySelector('.ds-flex[style*="margin-top"]'); if (buttonDiv) buttonDiv.remove(); } else { // For user messages, create a new div with only the text content from fbb737a4 contentDiv = document.createElement('div'); contentDiv.className = 'fbb737a4 ai-chat-content'; // Clone the div and remove export button and afb1eea3 before getting text const tempDiv = div.cloneNode(true); const exportButton = tempDiv.querySelector('.ai-export-button'); if (exportButton) exportButton.remove(); const afb1eea3 = tempDiv.querySelector('.afb1eea3'); if (afb1eea3) afb1eea3.remove(); contentDiv.textContent = tempDiv.textContent.trim(); } chatWrapper.appendChild(contentDiv); // Add avatar on the right for user messages if (!isAI) { const avatarClone = userAvatar.cloneNode(true); chatWrapper.appendChild(avatarClone); } topSection.appendChild(chatWrapper); }); let footerText = texts.footer; if (addCreatorInfo && creatorName) { footerText += ` — By ${creatorName}`; } const bottomSection = document.createElement('div'); bottomSection.textContent = footerText; bottomSection.style.padding = '10px'; bottomSection.style.textAlign = 'center'; bottomSection.style.fontSize = '14px'; bottomSection.style.fontFamily = 'Arial, sans-serif'; bottomSection.style.backgroundColor = colorScheme.bottom; bottomSection.style.color = colorScheme.textBottom; container.appendChild(topSection); container.appendChild(bottomSection); container.style.position = 'absolute'; container.style.left = '-9999px'; document.body.appendChild(container); try { const canvas = await html2canvas(container, { scale: 2, backgroundColor: null, useCORS: true, logging: false }); const link = document.createElement('a'); link.download = `chat_export_${new Date().toISOString().split('T')[0]}.png`; link.href = canvas.toDataURL('image/png'); link.click(); } catch (error) { console.error('Error generating image:', error); alert(texts.error); } document.body.removeChild(container); } // Initialize function init() { addStyles(); createFAB(); addExportButtonsToMessages(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();