Greasy Fork

Greasy Fork is available in English.

NodeSeek 银星公益图床增强脚本

在 NodeSeek 支持点击、拖拽和粘贴上传图片银星公益图床,并插入 Markdown 格式到编辑器

当前为 2025-03-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         NodeSeek 银星公益图床增强脚本
// @namespace    http://tampermonkey.net/
// @version      1.4
// @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.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;

    // 添加常驻提示文字(#cm-editor-wrapper)
    if (editorWrapper) {
        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';
        editorWrapper.style.position = 'relative';
        editorWrapper.appendChild(hint);
    }

    // 添加常驻提示文字(CodeMirror)
    if (codeMirror) {
        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';
        codeMirror.style.position = 'relative';
        codeMirror.appendChild(hint);
    }

    // 创建上传提示并显示倒计时
    function showUploadHint(container, fileSize) {
        if (container) {
            const uploadHint = document.createElement('div');
            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.id = 'upload-hint-' + (container === editorWrapper ? 'wrapper' : 'codemirror');

            // 计算预计上传时间(单位:秒)
            const bandwidth = 15 * 1024 * 1024 / 8; // 15 Mbps 转为字节每秒 (15 * 1024 * 1024 / 8 = 1.875 MB/s),可根据实际带宽调整
            const estimatedTime = Math.ceil(fileSize / bandwidth); // 文件大小(字节)除以带宽,向上取整
            let remainingTime = estimatedTime;

            uploadHint.textContent = `正在上传 (${(fileSize / (1024 * 1024)).toFixed(2)} MB),预计 ${remainingTime} 秒`;
            container.appendChild(uploadHint);

            // 启动倒计时
            const interval = setInterval(() => {
                if (remainingTime > 0) {
                    remainingTime--;
                    uploadHint.textContent = `正在上传 (${(fileSize / (1024 * 1024)).toFixed(2)} MB),预计 ${remainingTime} 秒`;
                }
            }, 1000);

            return { uploadHint, interval };
        }
    }

    // 移除上传提示
    function removeUploadHint(container, interval) {
        clearInterval(interval); // 停止倒计时
        const uploadHint = document.getElementById('upload-hint-' + (container === editorWrapper ? 'wrapper' : 'codemirror'));
        if (uploadHint) {
            uploadHint.remove();
        }
    }

    // 监听图片图标点击并屏蔽原有功能
    document.addEventListener('click', function(e) {
        const target = e.target.closest('span.toolbar-item.i-icon.i-icon-pic');
        if (target) {
            e.preventDefault();
            e.stopPropagation();
            fileInput.click();
        }
    }, true);

    // 文件选择后的处理
    fileInput.addEventListener('change', function(e) {
        if (e.target.files && e.target.files[0]) {
            const file = e.target.files[0];
            const formData = new FormData();
            formData.append('file', file);
            uploadToImageHost(formData, editorWrapper, file.size);
        }
    });

    // 拖拽上传功能(#cm-editor-wrapper)
    if (editorWrapper) {
        editorWrapper.addEventListener('dragover', (e) => {
            e.preventDefault();
            e.stopPropagation();
            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 = '';
            const files = e.dataTransfer.files;
            if (files && files[0] && files[0].type.startsWith('image/')) {
                const formData = new FormData();
                formData.append('file', files[0]);
                uploadToImageHost(formData, editorWrapper, files[0].size);
            }
        });
    }

    // 粘贴上传功能(#cm-editor-wrapper)
    if (editorWrapper) {
        editorWrapper.addEventListener('paste', (e) => {
            const items = (e.clipboardData || e.originalEvent.clipboardData).items;
            for (let i = 0; i < items.length; i++) {
                if (items[i].type.indexOf('image') !== -1) {
                    e.preventDefault();
                    const file = items[i].getAsFile();
                    if (file) {
                        const formData = new FormData();
                        formData.append('file', file);
                        uploadToImageHost(formData, editorWrapper, file.size);
                    }
                    break;
                }
            }
        });
    }

    // 拖拽上传功能(CodeMirror)
    if (codeMirror) {
        codeMirror.addEventListener('dragover', (e) => {
            e.preventDefault();
            e.stopPropagation();
            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 = '';
            const files = e.dataTransfer.files;
            if (files && files[0] && files[0].type.startsWith('image/')) {
                const formData = new FormData();
                formData.append('file', files[0]);
                uploadToImageHost(formData, codeMirror, files[0].size);
            }
        });
    }

    // 粘贴上传功能(CodeMirror)
    if (codeMirror) {
        codeMirror.addEventListener('paste', (e) => {
            const items = (e.clipboardData || e.originalEvent.clipboardData).items;
            for (let i = 0; i < items.length; i++) {
                if (items[i].type.indexOf('image') !== -1) {
                    e.preventDefault();
                    const file = items[i].getAsFile();
                    if (file) {
                        const formData = new FormData();
                        formData.append('file', file);
                        uploadToImageHost(formData, codeMirror, file.size);
                    }
                    break;
                }
            }
        });
    }

    // 上传到图床的函数
    function uploadToImageHost(formData, container, fileSize) {
        const { uploadHint, interval } = showUploadHint(container, fileSize);
        return new Promise((resolve, reject) => {
            const apiUrl = 'https://img.sss.wiki/api/v1/upload';
            const token = 'Bearer 9|aiSZmhAzf9u7k8slCHXVe8ZDpyH2earpsgQcgHoi';

            console.log('开始上传到:', apiUrl);
            console.log('使用 Token:', token);

            GM_xmlhttpRequest({
                method: 'POST',
                url: apiUrl,
                headers: {
                    'Authorization': token,
                    'Accept': 'application/json'
                },
                data: formData,
                onload: (response) => {
                    removeUploadHint(container, interval);
                    console.log('响应状态:', response.status);
                    console.log('响应内容:', response.responseText);
                    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 fileName = formData.get('file').name.split('.').slice(0, -1).join('.');
                            const markdownImage = `![${fileName}](${imageUrl})`;
                            console.log('上传成功,Markdown:', markdownImage);
                            insertToEditor(markdownImage);
                        } else {
                            console.error('上传成功但未获取到有效链接');
                        }
                        resolve();
                    } catch (error) {
                        console.error('解析响应错误:', error);
                        reject(error);
                    }
                },
                onerror: (error) => {
                    removeUploadHint(container, interval);
                    console.error('上传错误详情:', error);
                    reject(error);
                },
                ontimeout: () => {
                    removeUploadHint(container, interval);
                    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');
            }
        }
    }
})();