DeepFloodbeta

DeepFlood 控制面板(原NodeSeek控制面板)

油猴脚本
代码一点没改,GitHub仓库已死
支持CTRL+Enter发送消息
京东图片粘贴
代码高亮

// ==UserScript==
// @name         NodeSeek 功能面板(v5.8)
// @namespace    https://github.com/344LTD/NodeSeek-Control-Panel
// @version      5.8
// @author       344.LTD (https://344.ltd)
// @description  NodeSeek 功能面板,优化面板动画和图片上传功能
// @match        https://www.nodeseek.com/*
// @match        https://www.deepflood.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @connect      cdn.jsdelivr.net
// @connect      pic.jd.com
// @connect      feedback.jd.com
// @license      MIT
// @homepageURL  https://github.com/344LTD/NodeSeek-Control-Panel
// @supportURL   https://github.com/344LTD/NodeSeek-Control-Panel/issues
// ==/UserScript==

(function () {
    'use strict';

    // ---------------------
    // 初始化设置状态
    // ---------------------
    let ctrlEnterEnabled = true;
    let imgUploadEnabled = true;
    let codeHighlightEnabled = true;
    let newTabOpenEnabled = true; // 新增:新标签页打开功能状态

    // 尝试从存储中获取设置状态
    try {
        const savedCtrlEnter = localStorage.getItem('nsk_ctrlenter_enabled');
        const savedImgUpload = localStorage.getItem('nsk_imgupload_enabled');
        const savedCodeHighlight = localStorage.getItem('nsk_codehighlight_enabled');
        const savedNewTabOpen = localStorage.getItem('nsk_newtabopen_enabled'); // 新增

        if (savedCtrlEnter !== null) {
            ctrlEnterEnabled = savedCtrlEnter === 'true';
        }
        if (savedImgUpload !== null) {
            imgUploadEnabled = savedImgUpload === 'true';
        }
        if (savedCodeHighlight !== null) {
            codeHighlightEnabled = savedCodeHighlight === 'true';
        }
        if (savedNewTabOpen !== null) { // 新增
            newTabOpenEnabled = savedNewTabOpen === 'true';
        }
    } catch (e) {
        console.log('无法读取本地存储,使用默认设置');
    }

    // ---------------------
    // 创建控制面板 UI(隐藏)
    // ---------------------
    const panel = document.createElement("div");
    panel.id = "nsk-control-panel";
    panel.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        width: 830px;
        height: 500px;
        background: #fff;
        border: 2px solid #ccc;
        border-radius: 10px;
        box-shadow: 0 5px 20px rgba(0,0,0,0.3);
        transform: translate(-50%, -50%) scale(0.9);
        z-index: 10000;
        padding: 0;
        opacity: 0;
        display: none;
        flex-direction: column;
        font-family: sans-serif;
        transition: opacity 0.3s ease, transform 0.3s ease;
        pointer-events: none;
    `;

    panel.innerHTML = `
        <div style="background:#f0f0f0; padding:10px; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid #ccc;">
            <h2 style="margin:0;font-size:18px;">⚙️ NodeSeek 功能面板 v5.7</h2>
            <button id="nsk-close" style="border:none;background:#f44336;color:#fff;padding:5px 10px;border-radius:5px;cursor:pointer;">关闭</button>
        </div>
        <div style="padding:15px; flex:1; display:flex; flex-direction:column; gap:15px;">
            <div style="display:flex; gap:15px; flex:0 0 auto;">
                <div style="flex:1; border:1px solid #ccc; border-radius:5px; padding:10px; display:flex; justify-content:space-between; align-items:center; flex-direction:column;">
                    <span style="align-self:flex-start;font-weight:bold;margin-bottom:5px;">功能性</span>
                    <div style="width:100%; display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
                        <span>Ctrl+Enter 快捷发送(文章/评论/私信)</span>
                        <label class="switch">
                            <input type="checkbox" id="nsk-ctrlenter" ${ctrlEnterEnabled ? 'checked' : ''}>
                            <span class="slider"></span>
                        </label>
                    </div>
                    <div style="width:100%; display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
                        <span>京东图床(点击+粘贴+拖拽上传)(JPG/PNG/WEBP)</span>
                        <label class="switch">
                            <input type="checkbox" id="nsk-imgupload" ${imgUploadEnabled ? 'checked' : ''}>
                            <span class="slider"></span>
                        </label>
                    </div>
                    <div style="width:100%; display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
                        <span>代码高亮+复制按钮</span>
                        <label class="switch">
                            <input type="checkbox" id="nsk-codehighlight" ${codeHighlightEnabled ? 'checked' : ''}>
                            <span class="slider"></span>
                        </label>
                    </div>
                    <div style="width:100%; display:flex; justify-content:space-between; align-items:center;">
                        <span>页面链接新标签页打开</span>
                        <label class="switch">
                            <input type="checkbox" id="nsk-newtabopen" ${newTabOpenEnabled ? 'checked' : ''}>
                            <span class="slider"></span>
                        </label>
                    </div>
                </div>
                <div style="flex:1; border:1px solid #ccc; border-radius:5px; padding:10px; display:flex; justify-content:space-between; align-items:center; flex-direction:column;">
                    <span style="align-self:flex-start;font-weight:bold;margin-bottom:5px;">特殊性</span>
                </div>
            </div>
            <div style="flex:0 0 auto; border:1px solid #ccc; border-radius:5px; padding:10px; display:flex; justify-content:space-between; align-items:center; flex-direction:column;">
                <span style="align-self:flex-start;font-weight:bold;margin-bottom:5px;">杂项</span>
            </div>
            <div style="flex:0 0 auto; border:1px solid #ccc; border-radius:5px; padding:10px; display:flex; justify-content:space-between; align-items:center; flex-direction:column;">
                <span style="align-self:flex-start;font-weight:bold;margin-bottom:5px;">特别鸣谢(排名不分先后)</span>
                <div style="width:100%; display:flex; justify-content:space-between; align-items:center;">
                        <span><a href="//www.nodeseek.com/space/35533" target="_blank">NodeSeek-344</a>、<a href="//www.nodeseek.com/space/12024" target="_blank">NodeSeek-三七</a></span>
                        <br>
                        优化:点击上传返回纯URL,粘贴上传返回Markdown,拖拽上传返回Markdown
                </div>
            </div>
        </div>

        <style>
        .switch {
          position: relative;
          display: inline-block;
          width: 40px;
          height: 20px;
        }
        .switch input {display:none;}
        .slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: #ccc;
          transition: .4s;
          border-radius: 20px;
        }
        .slider:before {
          position: absolute;
          content: "";
          height: 16px;
          width: 16px;
          left: 2px;
          bottom: 2px;
          background-color: white;
          transition: .4s;
          border-radius: 50%;
        }
        input:checked + .slider {
          background-color: #4caf50;
        }
        input:checked + .slider:before {
          transform: translateX(20px);
        }
        </style>
    `;
    document.body.appendChild(panel);

    // ---------------------
    // 面板显示/隐藏函数
    // ---------------------
    function showPanel() {
        panel.style.display = "flex";
        setTimeout(() => {
            panel.style.opacity = "1";
            panel.style.transform = "translate(-50%, -50%) scale(1)";
            panel.style.pointerEvents = "auto";
        }, 10);
    }

    function hidePanel() {
        panel.style.opacity = "0";
        panel.style.transform = "translate(-50%, -50%) scale(0.9)";
        panel.style.pointerEvents = "none";
        setTimeout(() => {
            panel.style.display = "none";
        }, 300);
    }

    // ---------------------
    // 面板按钮
    // ---------------------
    const themeSwitcher = document.querySelector(".color-theme-switcher");
    if (themeSwitcher && themeSwitcher.parentNode) {
        const settingsBtn = document.createElement("div");
        settingsBtn.className = "nsk-settings-btn";
        settingsBtn.textContent = "⚙️";
        settingsBtn.style.cssText = "display:inline-block;margin-left:10px;cursor:pointer;font-size:18px;vertical-align:middle;";

        settingsBtn.addEventListener("click", showPanel);
        themeSwitcher.parentNode.insertBefore(settingsBtn, themeSwitcher.nextSibling);
    }

    // ---------------------
    // 关闭面板
    // ---------------------
    document.getElementById("nsk-close").addEventListener("click", hidePanel);

    // ---------------------
    // Ctrl+Enter 快捷发送(带状态保存)
    // ---------------------
    const ctrlEnterCheckbox = document.querySelector("#nsk-ctrlenter");
    if (ctrlEnterCheckbox) {
        // 设置初始状态
        ctrlEnterCheckbox.checked = ctrlEnterEnabled;

        ctrlEnterCheckbox.addEventListener("change", () => {
            ctrlEnterEnabled = ctrlEnterCheckbox.checked;

            // 保存设置到本地存储
            try {
                localStorage.setItem('nsk_ctrlenter_enabled', ctrlEnterEnabled.toString());
                console.log('✅ Ctrl+Enter 设置已保存:', ctrlEnterEnabled);
            } catch (e) {
                console.log('❌ 无法保存设置到本地存储');
            }
        });
    }

    // ---------------------
    // 图片上传功能(带状态保存)
    // ---------------------
    const imgUploadCheckbox = document.querySelector("#nsk-imgupload");
    if (imgUploadCheckbox) {
        // 设置初始状态
        imgUploadCheckbox.checked = imgUploadEnabled;

        imgUploadCheckbox.addEventListener("change", () => {
            imgUploadEnabled = imgUploadCheckbox.checked;

            // 保存设置到本地存储
            try {
                localStorage.setItem('nsk_imgupload_enabled', imgUploadEnabled.toString());
                console.log('✅ 图片上传设置已保存:', imgUploadEnabled);

                // 根据开关状态启用或禁用功能
                if (imgUploadEnabled) {
                    initImageUpload();
                } else {
                    removeImageUpload();
                }
            } catch (e) {
                console.log('❌ 无法保存设置到本地存储');
            }
        });

        // 初始加载时根据设置启用或禁用功能
        if (imgUploadEnabled) {
            setTimeout(initImageUpload, 1000);
        }
    }

    // ---------------------
    // 代码高亮功能(带状态保存)
    // ---------------------
    const codeHighlightCheckbox = document.querySelector("#nsk-codehighlight");
    if (codeHighlightCheckbox) {
        // 设置初始状态
        codeHighlightCheckbox.checked = codeHighlightEnabled;

        codeHighlightCheckbox.addEventListener("change", () => {
            codeHighlightEnabled = codeHighlightCheckbox.checked;

            // 保存设置到本地存储
            try {
                localStorage.setItem('nsk_codehighlight_enabled', codeHighlightEnabled.toString());
                console.log('✅ 代码高亮设置已保存:', codeHighlightEnabled);

                // 根据开关状态启用或禁用功能
                if (codeHighlightEnabled) {
                    initCodeHighlight();
                } else {
                    removeCodeHighlight();
                }
            } catch (e) {
                console.log('❌ 无法保存设置到本地存储');
            }
        });

        // 初始加载时根据设置启用或禁用功能
        if (codeHighlightEnabled) {
            setTimeout(initCodeHighlight, 1000);
        }
    }

    // ---------------------
    // 新标签页打开功能(带状态保存)
    // ---------------------
    const newTabOpenCheckbox = document.querySelector("#nsk-newtabopen");
    if (newTabOpenCheckbox) {
        // 设置初始状态
        newTabOpenCheckbox.checked = newTabOpenEnabled;

        newTabOpenCheckbox.addEventListener("change", () => {
            newTabOpenEnabled = newTabOpenCheckbox.checked;

            // 保存设置到本地存储
            try {
                localStorage.setItem('nsk_newtabopen_enabled', newTabOpenEnabled.toString());
                console.log('✅ 新标签页打开设置已保存:', newTabOpenEnabled);

                // 根据开关状态启用或禁用功能
                if (newTabOpenEnabled) {
                    initNewTabOpen();
                } else {
                    removeNewTabOpen();
                }
            } catch (e) {
                console.log('❌ 无法保存设置到本地存储');
            }
        });

        // 初始加载时根据设置启用或禁用功能
        if (newTabOpenEnabled) {
            setTimeout(initNewTabOpen, 1000);
        }
    }

    // ---------------------
    // 新标签页打开功能实现
    // ---------------------
    function initNewTabOpen() {
        console.log("NodeSeek 新标签页打开功能已启动");

        function handleLinkClick(e) {
            if (!newTabOpenEnabled) return;

            const target = e.target.closest('a');
            if (!target) return;

            // 排除已经设置了target="_blank"的链接
            if (target.getAttribute('target') === '_blank') return;

            // 排除非nodeseek.com的链接
            if (target.href && !target.href.includes('nodeseek.com')) return;

            // 排除可能影响功能的特殊链接(如登录、登出等)
            if (target.href.includes('/login') || target.href.includes('/logout')) return;

            e.preventDefault();
            e.stopPropagation();
            window.open(target.href, '_blank');
        }

        document.addEventListener('click', handleLinkClick, true);

        // 保存引用以便后续移除
        window.nskNewTabHandler = handleLinkClick;
    }

    function removeNewTabOpen() {
        console.log("移除新标签页打开功能");

        if (window.nskNewTabHandler) {
            document.removeEventListener('click', window.nskNewTabHandler, true);
            delete window.nskNewTabHandler;
        }
    }

    // ---------------------
    // 图片上传功能实现(优化返回格式+拖拽上传)
    // ---------------------
    function initImageUpload() {
        console.log("NodeSeek 图片上传助手已启动 (支持点击+粘贴+拖拽上传)");

        // 京东图片上传API
        const uploadUrl = 'https://pic.jd.com/0/32ac1cd9ca1543e2a9cce60a4c9be94e';
        const imgPreUrl = 'https://img20.360buyimg.com/openfeedback/';

        // 模拟CURL方式上传文件
        function uploadToJD(file, callback) {
            console.log("开始上传图片:", file.name, "大小:", file.size, "类型:", file.type);

            // 检查文件类型
            if (!file.type.match(/^image\/(jpeg|png|webp)$/)) {
                callback('只支持 JPG、PNG 或 WEBP 格式的图片', null);
                return;
            }

            // 检查文件大小 (限制为 5MB)
            if (file.size > 5 * 1024 * 1024) {
                callback('图片大小不能超过 5MB', null);
                return;
            }

            // 构建FormData
            const formData = new FormData();
            formData.append('file', file, file.name);

            // 使用GM_xmlhttpRequest发送请求
            GM_xmlhttpRequest({
                method: 'POST',
                url: uploadUrl,
                data: formData,
                headers: {
                    'Origin': 'https://feedback.jd.com',
                    'Referer': 'https://feedback.jd.com/',
                    'Accept': 'application/json, text/javascript, */*; q=0.01'
                },
                onload: function(response) {
                    console.log("上传响应状态:", response.status);
                    console.log("上传响应内容:", response.responseText);

                    try {
                        const result = JSON.parse(response.responseText);

                        if (response.status >= 200 && response.status < 300) {
                            // 处理京东返回的路径格式
                            let imageUrl;
                            if (result.msg && result.msg.startsWith('jfs/')) {
                                imageUrl = imgPreUrl + result.msg;
                            } else if (result.url) {
                                imageUrl = result.url;
                            } else {
                                callback('服务器返回了未知格式: ' + response.responseText, null);
                                return;
                            }

                            console.log("上传成功:", imageUrl);
                            callback(null, imageUrl);
                        } else {
                            callback('上传失败: ' + (result.msg || response.statusText), null);
                        }
                    } catch (e) {
                        callback('解析响应失败: ' + e.message, null);
                    }
                },
                onerror: function(error) {
                    callback('上传错误: ' + (error.statusText || '网络错误'), null);
                },
                ontimeout: function() {
                    callback('上传超时 (30秒)', null);
                },
                timeout: 30000
            });
        }

        // 点击上传逻辑(返回纯URL,不带http/https)
        function handleImageClick(e) {
            if (!imgUploadEnabled) return;

            if (e.target.closest(".toolbar-item.i-icon.i-icon-pic")) {
                const input = document.createElement("input");
                input.type = "file";
                input.accept = "image/jpeg,image/png,image/webp";
                input.onchange = () => {
                    const file = input.files[0];
                    if (!file) return;

                    // 显示上传状态
                    showUploadStatus("图片上传中...");

                    uploadToJD(file, (err, url) => {
                        if (err) {
                            console.error("上传失败详情:", err);
                            showUploadStatus("上传失败: " + err, true);
                            return;
                        }

                        console.log("上传成功:", url);

                        // 移除http://或https://前缀
                        const pureUrl = url.replace(/^https?:\/\//i, '');

                        // 点击上传时只返回纯URL
                        if (insertToEditor(pureUrl)) {
                            showUploadStatus("上传成功!", false);
                        } else {
                            // 复制到剪贴板
                            copyToClipboard(pureUrl, "图片链接已复制到剪贴板");
                        }
                    });
                };
                input.click();
            }
        }

        // 粘贴上传逻辑(返回Markdown格式)
        function handleImagePaste(e) {
            if (!imgUploadEnabled) return;

            const items = e.clipboardData?.items;
            if (!items) return;

            for (const item of items) {
                if (item.type.indexOf('image') !== -1) {
                    const file = item.getAsFile();
                    if (!file) return;

                    // 显示上传状态
                    showUploadStatus("图片上传中...");

                    uploadToJD(file, (err, url) => {
                        if (err) {
                            console.error("粘贴上传失败详情:", err);
                            showUploadStatus("上传失败: " + err, true);
                            return;
                        }

                        console.log("粘贴上传成功:", url);

                        // 粘贴上传时返回Markdown格式
                        const markdown = `![image](${url})`;

                        if (insertToEditor(markdown)) {
                            showUploadStatus("上传成功!", false);
                        } else {
                            // 复制到剪贴板
                            copyToClipboard(markdown, "Markdown链接已复制到剪贴板");
                        }
                    });
                    e.preventDefault();
                    break;
                }
            }
        }

        // 拖拽上传逻辑(返回Markdown格式)
        function handleImageDrop(e) {
            if (!imgUploadEnabled) return;

            // 检查是否有文件被拖拽
            const files = e.dataTransfer?.files;
            if (!files || files.length === 0) return;

            const file = files[0];
            if (!file.type.match(/^image\/(jpeg|png|webp)$/)) return;

            e.preventDefault();
            e.stopPropagation();

            // 显示上传状态
            showUploadStatus("图片上传中...");

            uploadToJD(file, (err, url) => {
                if (err) {
                    console.error("拖拽上传失败详情:", err);
                    showUploadStatus("上传失败: " + err, true);
                    return;
                }

                console.log("拖拽上传成功:", url);

                // 拖拽上传时返回Markdown格式
                const markdown = `![image](${url})`;

                if (insertToEditor(markdown)) {
                    showUploadStatus("上传成功!", false);
                } else {
                    // 复制到剪贴板
                    copyToClipboard(markdown, "Markdown链接已复制到剪贴板");
                }
            });
        }

        // 防止默认拖放行为
        function handleDragOver(e) {
            if (imgUploadEnabled && e.dataTransfer.types.includes('Files')) {
                e.preventDefault();
                e.dataTransfer.dropEffect = 'copy';
            }
        }

        // 插入到编辑器
        function insertToEditor(content) {
            // 尝试找到各种可能的编辑器
            let editor = document.querySelector("textarea");
            if (!editor) {
                editor = document.querySelector("[contenteditable='true']") ||
                        document.querySelector(".CodeMirror") ||
                        document.querySelector(".editor") ||
                        document.querySelector(".message-input") ||
                        document.querySelector(".comment-textarea");
            }

            if (editor) {
                if (editor.tagName === 'TEXTAREA') {
                    // 处理textarea
                    const start = editor.selectionStart || editor.value.length;
                    const end = editor.selectionEnd || editor.value.length;
                    const before = editor.value.substring(0, start);
                    const after = editor.value.substring(end);
                    editor.value = before + content + after;

                    // 设置光标位置
                    const cursorPos = start + content.length;
                    editor.selectionStart = editor.selectionEnd = cursorPos;

                    // 触发输入事件
                    editor.dispatchEvent(new Event("input", { bubbles: true }));
                    editor.dispatchEvent(new Event("change", { bubbles: true }));

                    return true;
                } else if (editor.isContentEditable) {
                    // 处理contenteditable元素
                    const selection = window.getSelection();
                    if (selection.rangeCount > 0) {
                        const range = selection.getRangeAt(0);
                        range.deleteContents();
                        const textNode = document.createTextNode(content);
                        range.insertNode(textNode);

                        // 移动光标到插入的内容之后
                        range.setStartAfter(textNode);
                        range.setEndAfter(textNode);
                        selection.removeAllRanges();
                        selection.addRange(range);
                    }

                    // 触发输入事件
                    editor.dispatchEvent(new Event("input", { bubbles: true }));

                    return true;
                }
            }

            return false;
        }

        // 显示上传状态
        function showUploadStatus(message, isError = false) {
            // 移除现有的状态提示
            const existingStatus = document.getElementById('nsk-upload-status');
            if (existingStatus) {
                existingStatus.remove();
            }

            const status = document.createElement('div');
            status.id = 'nsk-upload-status';
            status.style.cssText = `
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 10px 15px;
                background: ${isError ? '#ff4444' : '#4CAF50'};
                color: white;
                border-radius: 5px;
                z-index: 10001;
                font-family: sans-serif;
                box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            `;
            status.textContent = message;
            document.body.appendChild(status);

            // 3秒后自动消失
            setTimeout(() => {
                if (status.parentNode) {
                    status.remove();
                }
            }, 3000);
        }

        // 复制到剪贴板
        function copyToClipboard(text, successMessage) {
            navigator.clipboard.writeText(text).then(() => {
                showUploadStatus(successMessage, false);
            }).catch(() => {
                showUploadStatus("请手动复制: " + text, false);
            });
        }

        // 添加事件监听
        document.addEventListener("click", handleImageClick);
        document.addEventListener("paste", handleImagePaste);
        document.addEventListener("drop", handleImageDrop);
        document.addEventListener("dragover", handleDragOver);

        // 保存引用以便后续移除
        window.nskImageHandlers = {
            click: handleImageClick,
            paste: handleImagePaste,
            drop: handleImageDrop,
            dragover: handleDragOver
        };

        console.log("图片上传功能已启用 (支持点击+粘贴+拖拽上传)");
    }

    function removeImageUpload() {
        console.log("移除图片上传功能");

        // 移除事件监听
        if (window.nskImageHandlers) {
            document.removeEventListener("click", window.nskImageHandlers.click);
            document.removeEventListener("paste", window.nskImageHandlers.paste);
            document.removeEventListener("drop", window.nskImageHandlers.drop);
            document.removeEventListener("dragover", window.nskImageHandlers.dragover);
            delete window.nskImageHandlers;
        }

        // 移除状态提示
        const status = document.getElementById('nsk-upload-status');
        if (status) {
            status.remove();
        }
    }

    // ---------------------
    // 代码高亮功能实现
    // ---------------------
    function initCodeHighlight() {
        console.log("NodeSeek 代码高亮功能已启动");

        // --- 配置部分 ---
        const HLJS_CSS_URL = "https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/base16/humanoid-light.min.css";
        const HLJS_JS_URL = "https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js";

        // --- 复制按钮的样式 ---
        GM_addStyle(`
            pre > code.hljs {
                position: relative;
            }
            .copy-code-button {
                position: absolute;
                top: 0.5em;
                right: 0.5em;
                padding: 4px 8px;
                font-size: 12px;
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
                color: #ccc;
                background-color: #444;
                border: 1px solid #666;
                border-radius: 4px;
                cursor: pointer;
                opacity: 0;
                transition: opacity 0.2s ease-in-out, background-color 0.2s, color 0.2s, border-color 0.2s;
                z-index: 10;
            }
            pre:hover .copy-code-button {
                opacity: 1;
            }
            .copy-code-button:hover {
                background-color: #555;
                color: #fff;
            }
            .copy-code-button.copied {
                background-color: #28a745;
                color: white;
                border-color: #28a745;
            }
        `);

        let hljsLoaded = false;
        let hljsLoading = false;

        function debounce(func, delay) {
            let timeout;
            return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => func.apply(this, args), delay);
            };
        }

        function loadScript(url, callback) {
            if (hljsLoaded) {
                if (callback) callback();
                return;
            }
            if (hljsLoading) {
                document.addEventListener('hljs-loaded', callback, { once: true });
                return;
            }
            hljsLoading = true;
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                onload: function(response) {
                    const script = document.createElement('script');
                    script.textContent = response.responseText;
                    document.head.appendChild(script).remove();
                    hljsLoaded = true;
                    hljsLoading = false;
                    console.log(`[Auto Highlighter] Loaded JS: ${url}`);
                    document.dispatchEvent(new Event('hljs-loaded'));
                    if (callback) callback();
                },
                onerror: function(response) {
                    console.error(`[Auto Highlighter] Failed to load script ${url}:`, response);
                    hljsLoading = false;
                }
            });
        }

        // --- 添加复制按钮的函数 ---
        function addCopyButtons() {
            document.querySelectorAll('pre > code.hljs').forEach(codeBlock => {
                if (codeBlock.querySelector('.copy-code-button')) {
                    return;
                }

                const button = document.createElement('button');
                button.className = 'copy-code-button';
                button.textContent = '复制';

                button.addEventListener('click', (event) => {
                    const codeClone = codeBlock.cloneNode(true);
                    const buttonInClone = codeClone.querySelector('.copy-code-button');
                    if (buttonInClone) {
                        buttonInClone.remove();
                    }
                    const codeToCopy = codeClone.innerText;

                    navigator.clipboard.writeText(codeToCopy).then(() => {
                        button.textContent = '已复制!';
                        button.classList.add('copied');
                        setTimeout(() => {
                            button.textContent = '复制';
                            button.classList.remove('copied');
                        }, 2000);
                    }).catch(err => {
                        console.error('复制失败: ', err);
                        button.textContent = '错误';
                    });
                });

                codeBlock.appendChild(button);
            });
        }

        function findAndHighlight() {
            const codeBlocks = document.querySelectorAll('pre > code:not(.hljs)');
            if (codeBlocks.length > 0) {
                console.log(`[Auto Highlighter] Found ${codeBlocks.length} unhighlighted code blocks.`);
                loadScript(HLJS_JS_URL, () => {
                    if (typeof hljs !== 'undefined') {
                        console.log('[Auto Highlighter] Highlighting now...');
                        codeBlocks.forEach(element => {
                            hljs.highlightElement(element);
                        });
                        console.log('[Auto Highlighter] Highlighting complete.');
                        addCopyButtons();
                    } else {
                        console.warn('[Auto Highlighter] hljs not available for highlighting.');
                    }
                });
            }
            addCopyButtons();
        }

        // --- 启动逻辑 ---
        GM_addStyle('@import url("' + HLJS_CSS_URL + '");');
        const debouncedFindAndHighlight = debounce(findAndHighlight, 300);
        setTimeout(findAndHighlight, 100);
        window.addEventListener('load', findAndHighlight);

        const observer = new MutationObserver(() => {
            debouncedFindAndHighlight();
        });

        observer.observe(document.body, { childList: true, subtree: true });

        // 保存引用以便后续移除
        window.nskCodeHighlight = {
            observer: observer,
            debouncedFindAndHighlight: debouncedFindAndHighlight
        };

        console.log("代码高亮功能已启用");
    }

    function removeCodeHighlight() {
        console.log("移除代码高亮功能");

        // 移除观察器
        if (window.nskCodeHighlight && window.nskCodeHighlight.observer) {
            window.nskCodeHighlight.observer.disconnect();
        }

        // 移除事件监听
        if (window.nskCodeHighlight && window.nskCodeHighlight.debouncedFindAndHighlight) {
            window.removeEventListener('load', window.nskCodeHighlight.debouncedFindAndHighlight);
        }

        // 移除复制按钮
        document.querySelectorAll('.copy-code-button').forEach(button => {
            button.remove();
        });

        // 移除高亮样式
        document.querySelectorAll('code.hljs').forEach(code => {
            code.classList.remove('hljs');
        });

        // 移除样式
        const styles = document.querySelectorAll('style');
        styles.forEach(style => {
            if (style.textContent.includes('copy-code-button') ||
                style.textContent.includes('hljs')) {
                style.remove();
            }
        });

        delete window.nskCodeHighlight;
    }

    // ---------------------
    // Ctrl+Enter 快捷发送
    // ---------------------
    document.addEventListener("keydown", function (e) {
        if (!ctrlEnterEnabled) return;
        if (e.ctrlKey && e.key === "Enter") {
            const active = document.activeElement;
            const isInText = active && (
                active.tagName === "TEXTAREA" ||
                active.tagName === "INPUT" ||
                active.closest(".CodeMirror")
            );
            if (!isInText) return;

            e.preventDefault();

            let sendBtn =
                document.querySelector(".message-input .btn") ||
                document.querySelector("button.btn") ||
                [...document.querySelectorAll("button, div")].find(el =>
                    el.innerText.includes("发布") || el.innerText.includes("回复") || el.innerText.includes("发送")
                );

            if (sendBtn) {
                sendBtn.click();
                console.log("✅ Ctrl+Enter 已触发发送/发布");
            } else {
                console.log("❌ 未找到发送按钮");
            }
        }
    });

})();
12
12