油猴脚本
代码一点没改,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 = ``;
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 = ``;
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("❌ 未找到发送按钮");
}
}
});
})();
@NodeSeekkkk #10
不,你直接复制粘贴就行了
CTRL+Enter发送消息测试
图片粘贴测试
@bwgserver #6
我之前在NS发过,直接添加个域名就行
bd
好东西
好贴bd
增加个include域名就行了吧
老哥也太能写了吧
@zhxhwyzh14 #4
是的呢
可以
直接加上这一行就行了是吗
// @match https://www.deepflood.com/*