Greasy Fork

Greasy Fork is available in English.

剪贴板图片上传lsky图床-Nodeseek

Upload clipboard images to a configurable image host, auto-fetch token if missing or expired

目前为 2025-03-11 提交的版本,查看 最新版本

// ==UserScript==
// @name         剪贴板图片上传lsky图床-Nodeseek
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Upload clipboard images to a configurable image host, auto-fetch token if missing or expired
// @author       You
// @match        *://*.nodeseek.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @connect      *
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 配置项
    let config = {
        baseUrl: GM_getValue('baseUrl', ''),
        token: GM_getValue('token', ''),
        email: GM_getValue('email', ''),
        password: GM_getValue('password', ''),
        strategyId: GM_getValue('strategyId', 1) // 默认策略ID
    };

    // 注册菜单以更改设置
    GM_registerMenuCommand("设置lsky图床地址", function() {
        let newUrl = prompt("请输入图床地址", config.baseUrl);
        if (newUrl) {
            GM_setValue('baseUrl', newUrl);
            config.baseUrl = newUrl;
        }
    });

    GM_registerMenuCommand("设置账户", function() {
        let newEmail = prompt("请输入邮箱", config.email);
        if (newEmail) {
            GM_setValue('email', newEmail);
            config.email = newEmail;
        }
    });

    GM_registerMenuCommand("设置密码", function() {
        let newPassword = prompt("请输入密码", config.password);
        if (newPassword) {
            GM_setValue('password', newPassword);
            config.password = newPassword;
        }
    });

    GM_registerMenuCommand("设置策略ID", function() {
        let newStrategyId = prompt("请输入新的策略ID", config.strategyId);
        if (newStrategyId) {
            GM_setValue('strategyId', newStrategyId);
            config.strategyId = newStrategyId;
        }
    });

    async function getToken() {
        return new Promise((resolve, reject) => {
            console.log("尝试获取 Token...");
            GM_xmlhttpRequest({
                method: 'POST',
                url: `${config.baseUrl} kens`,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                data: JSON.stringify({
                    email: config.email,
                    password: config.password
                }),
                onload: function(response) {
                    let res;
                    try {
                        res = JSON.parse(response.responseText);
                    } catch (e) {
                        console.error("解析 Token 响应失败", e);
                        return reject("解析 Token 失败");
                    }

                    if (res.status && res.data && res.data.token) {
                        GM_setValue('token', res.data.token);
                        config.token = res.data.token;
                        console.log("Token 获取成功");
                        resolve(res.data.token);
                    } else {
                        console.error("获取 Token 失败: ", res.message);
                        reject(res.message || "未知错误");
                    }
                },
                onerror: function(err) {
                    console.error("获取 Token 请求失败", err);
                    reject("网络错误");
                }
            });
        });
    }

    document.addEventListener('paste', async (event) => {
        let items = (event.clipboardData || event.originalEvent.clipboardData).items;
        for (let item of items) {
            if (item.type.indexOf('image') !== -1) {
                let file = item.getAsFile();
                console.log("检测到剪贴板图片,开始上传...");

                // 确保有 token
                if (!config.token) {
                    console.log("Token 缺失,尝试获取...");
                    try {
                        await getToken();
                    } catch (e) {
                        console.error("无法获取 Token: ", e);
                        return;
                    }
                }

                let url = await uploadImage(file);
                if (url) {
                    insertText(url);
                }
            }
        }
    });

    async function uploadImage(file) {
        return new Promise(async (resolve, reject) => {
            let reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function () {
                let base64Data = reader.result.split(',')[1];  // 获取 Base64 数据
                let boundary = "----WebKitFormBoundary" + Math.random().toString(36).substr(2);

                let body = `--${boundary}\r\n` +
                           `Content-Disposition: form-data; name="file"; filename="image.png"\r\n` +
                           `Content-Type: image/png\r\n\r\n` +
                           `${base64Data}\r\n` +
                           `--${boundary}--`;

                function doUpload() {
                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: `${config.baseUrl}/api/v1/upload`,
                        headers: {
                            'Authorization': `Bearer ${config.token}`,
                            'Content-Type': `multipart/form-data; boundary=${boundary}`,
                            'Accept': 'application/json'
                        },
                        data: body,
                        onload: async function(response) {
                            let res;
                            try {
                                res = JSON.parse(response.responseText);
                            } catch (e) {
                                console.error("解析上传响应失败", e);
                                return reject("解析失败");
                            }

                            if (res.status && res.data && res.data.links && res.data.links.markdown) {
                                console.log("图片上传成功: ", res.data.links.url);
                                resolve(res.data.links.markdown);
                            } else if (res.code === 401) { // Token 失效
                                console.warn("Token 失效,尝试重新获取...");
                                try {
                                    await getToken();
                                    console.log("Token 更新成功,重新上传...");
                                    doUpload(); // 重新尝试上传
                                } catch (err) {
                                    console.error("重新获取 Token 失败: ", err);
                                    reject("Token 失效,无法上传");
                                }
                            } else {
                                console.error("图片上传失败: ", res.message);
                                reject(res.message || "上传失败");
                            }
                        },
                        onerror: function(err) {
                            console.error("上传请求失败", err);
                            reject("网络错误");
                        }
                    });
                }

                doUpload();
            };
        });
    }

    function insertText(text) {
        let activeElement = document.activeElement;
        if (activeElement) {
            if (activeElement.tagName === 'TEXTAREA' || activeElement.tagName === 'INPUT') {
                let start = activeElement.selectionStart;
                let end = activeElement.selectionEnd;
                activeElement.value = activeElement.value.substring(0, start) + text + activeElement.value.substring(end);
                activeElement.selectionStart = activeElement.selectionEnd = start + text.length;
            } else if (activeElement.isContentEditable) {
                let range = document.getSelection().getRangeAt(0);
                let textNode = document.createTextNode(text);
                range.deleteContents();
                range.insertNode(textNode);
                range.setStartAfter(textNode);
                range.setEndAfter(textNode);
                let selection = document.getSelection();
                selection.removeAllRanges();
                selection.addRange(range);
            }
        }
    }

})();