你需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
你需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
你需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
你需要先安装一款用户样式管理器扩展后才能安装此样式。
你需要先安装一款用户样式管理器扩展后才能安装此样式。
你需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已安装用户样式管理器,立即安装用户样式!)
// ==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
// ==/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 = ``;
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');
}
}
}
})();