// ==UserScript== // @name NodeSeek 银星公益图床增强脚本 // @namespace http://tampermonkey.net/ // @version 1.7 // @description 在 NodeSeek 支持点击、拖拽和粘贴上传图片银星公益图床,并插入 Markdown 格式到编辑器 // @author ZhangBreeze // @match https://www.nodeseek.com/* // @grant GM_xmlhttpRequest // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 创建文件输入元素(支持多选) const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.accept = 'image/*'; fileInput.multiple = true; fileInput.style.display = 'none'; document.body.appendChild(fileInput); // 获取编辑器区域 const editorWrapper = document.querySelector('#cm-editor-wrapper'); const codeMirror = document.querySelector('.CodeMirror.cm-s-default.cm-s-nsk.CodeMirror-wrap.CodeMirror-overlayscroll'); const cmInstance = document.querySelector('.CodeMirror')?.CodeMirror; // 添加常驻提示文字(避免重叠) function addUploadHint(container) { if (!container) return; const hint = document.createElement('div'); hint.textContent = '支持拖拽或粘贴上传图片'; hint.style.position = 'absolute'; hint.style.bottom = '5px'; hint.style.right = '5px'; hint.style.color = '#888'; hint.style.fontSize = '12px'; hint.style.zIndex = '10'; hint.style.pointerEvents = 'none'; container.style.position = 'relative'; container.appendChild(hint); } // 优先在 #cm-editor-wrapper 添加提示,若不存在则在 .CodeMirror 添加 if (editorWrapper) { addUploadHint(editorWrapper); } else if (codeMirror) { addUploadHint(codeMirror); } // 创建上传提示 function showUploadHint(container, fileCount) { if (!container) return; const existingHints = document.querySelectorAll('[id^="upload-hint-"]'); existingHints.forEach(hint => hint.remove()); const uploadHint = document.createElement('div'); uploadHint.textContent = `正在上传 ${fileCount} 张图片,请稍等`; uploadHint.style.position = 'absolute'; uploadHint.style.top = '50%'; uploadHint.style.left = '50%'; uploadHint.style.transform = 'translate(-50%, -50%)'; uploadHint.style.color = '#666'; uploadHint.style.fontSize = '14px'; uploadHint.style.background = 'rgba(0, 0, 0, 0.1)'; uploadHint.style.padding = '5px 10px'; uploadHint.style.borderRadius = '3px'; uploadHint.style.zIndex = '20'; uploadHint.style.maxWidth = '80%'; uploadHint.style.whiteSpace = 'nowrap'; uploadHint.style.overflow = 'hidden'; uploadHint.style.textOverflow = 'ellipsis'; uploadHint.id = 'upload-hint-' + (container === editorWrapper ? 'wrapper' : 'codemirror'); container.appendChild(uploadHint); } // 移除上传提示 function removeUploadHint(container) { const uploadHint = document.getElementById('upload-hint-' + (container === editorWrapper ? 'wrapper' : 'codemirror')); if (uploadHint) uploadHint.remove(); } // 防重锁 let isUploading = false; // 监听图片图标点击并屏蔽原有功能 document.addEventListener('click', function(e) { const target = e.target.closest('span.toolbar-item.i-icon.i-icon-pic'); if (target && !isUploading) { e.preventDefault(); e.stopPropagation(); fileInput.click(); } }, true); // 文件选择后的处理(支持多张) fileInput.addEventListener('change', function(e) { if (e.target.files && e.target.files.length > 0 && !isUploading) { isUploading = true; const files = Array.from(e.target.files); uploadMultipleFiles(files, editorWrapper || codeMirror).finally(() => { isUploading = false; fileInput.value = ''; }); } }); // 拖拽上传功能(#cm-editor-wrapper) if (editorWrapper) { editorWrapper.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); if (!isUploading) editorWrapper.style.border = '2px dashed #000'; }); editorWrapper.addEventListener('dragleave', (e) => { e.preventDefault(); e.stopPropagation(); editorWrapper.style.border = ''; }); editorWrapper.addEventListener('drop', (e) => { e.preventDefault(); e.stopPropagation(); editorWrapper.style.border = ''; if (e.dataTransfer.files && e.dataTransfer.files.length > 0 && !isUploading) { isUploading = true; const files = Array.from(e.dataTransfer.files).filter(file => file.type.startsWith('image/')); if (files.length > 0) { uploadMultipleFiles(files, editorWrapper).finally(() => isUploading = false); } else { isUploading = false; } } }); } // 粘贴上传功能(#cm-editor-wrapper) if (editorWrapper) { editorWrapper.addEventListener('paste', (e) => { const items = (e.clipboardData || e.originalEvent.clipboardData).items; const imageFiles = []; for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { const file = items[i].getAsFile(); if (file) imageFiles.push(file); } } if (imageFiles.length > 0 && !isUploading) { e.preventDefault(); isUploading = true; uploadMultipleFiles(imageFiles, editorWrapper).finally(() => isUploading = false); } }); } // 拖拽上传功能(CodeMirror) if (codeMirror) { codeMirror.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); if (!isUploading) codeMirror.style.border = '2px dashed #000'; }); codeMirror.addEventListener('dragleave', (e) => { e.preventDefault(); e.stopPropagation(); codeMirror.style.border = ''; }); codeMirror.addEventListener('drop', (e) => { e.preventDefault(); e.stopPropagation(); codeMirror.style.border = ''; if (e.dataTransfer.files && e.dataTransfer.files.length > 0 && !isUploading) { isUploading = true; const files = Array.from(e.dataTransfer.files).filter(file => file.type.startsWith('image/')); if (files.length > 0) { uploadMultipleFiles(files, codeMirror).finally(() => isUploading = false); } else { isUploading = false; } } }); } // 粘贴上传功能(CodeMirror) if (codeMirror) { codeMirror.addEventListener('paste', (e) => { const items = (e.clipboardData || e.originalEvent.clipboardData).items; const imageFiles = []; for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { const file = items[i].getAsFile(); if (file) imageFiles.push(file); } } if (imageFiles.length > 0 && !isUploading) { e.preventDefault(); isUploading = true; uploadMultipleFiles(imageFiles, codeMirror).finally(() => isUploading = false); } }); } // 上传多张图片 async function uploadMultipleFiles(files, container) { if (files.length === 0) return; showUploadHint(container, files.length); const uploadPromises = files.map(file => { const formData = new FormData(); formData.append('file', file); return uploadToImageHost(formData, file.name); }); try { await Promise.all(uploadPromises); } catch (error) { console.error('批量上传失败:', error); } finally { removeUploadHint(container); } } // 上传单张图片到图床 function uploadToImageHost(formData, fileName) { return new Promise((resolve, reject) => { const apiUrl = 'https://img.sss.wiki/api/v1/upload'; const token = 'Bearer 9|aiSZmhAzf9u7k8slCHXVe8ZDpyH2earpsgQcgHoi'; GM_xmlhttpRequest({ method: 'POST', url: apiUrl, headers: { 'Authorization': token, 'Accept': 'application/json' }, data: formData, onload: (response) => { try { const jsonResponse = JSON.parse(response.responseText); if (response.status === 200 && jsonResponse && jsonResponse.data && jsonResponse.data.links && jsonResponse.data.links.url) { const imageUrl = jsonResponse.data.links.url; const markdownImage = `![${fileName.split('.').slice(0, -1).join('.')}](${imageUrl})`; console.log('上传成功,Markdown:', markdownImage); insertToEditor(markdownImage); resolve(); } else { console.error('上传成功但未获取到有效链接'); reject(new Error('Invalid response')); } } catch (error) { console.error('解析响应错误:', error); reject(error); } }, onerror: (error) => { console.error('上传错误详情:', error); reject(error); }, ontimeout: () => { console.error('请求超时'); reject(new Error('Timeout')); }, timeout: 10000 }); }); } // 将 Markdown 插入到 CodeMirror 编辑器 function insertToEditor(markdown) { if (cmInstance) { const cursor = cmInstance.getCursor(); cmInstance.replaceRange(markdown + '\n', cursor); console.log('已插入 Markdown 到编辑器'); } else { const editable = document.querySelector('.CodeMirror textarea') || document.querySelector('textarea'); if (editable) { editable.value += markdown + '\n'; } else { console.error('未找到可编辑的 CodeMirror 实例或 textarea'); } } } })();