返回首頁 

Greasy Fork is available in English.

NodeSeek 帖子后台打开

在后台新窗口打开 NodeSeek 帖子标题,可配置状态显示


Installer dette script?
// ==UserScript==// @name         NodeSeek 帖子后台打开// @version      1.7.0// @description  在后台新窗口打开 NodeSeek 帖子标题,可配置状态显示// @match        https://www.nodeseek.com/*// @grant        GM_setValue// @grant        GM_getValue// @grant        GM_registerMenuCommand// @license      MIT// @author       Gh0st&Claude// @namespace https://greasyfork.org/users/118214// ==/UserScript==/*MIT LicenseCopyright (c) Gh0st&ClaudePermission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.*/(function() {'use strict';// 配置常量const CONFIG = {DEFAULT_ENABLED: true,DEFAULT_STATUS_VISIBLE: true,DEBOUNCE_DELAY: 300,STATUS_STYLES: {position: 'fixed',bottom: '20px',right: '20px',backgroundColor: 'rgba(0,0,0,0.7)',color: 'white',padding: '10px',borderRadius: '5px',zIndex: '9999',cursor: 'pointer',display: 'none'}};// 国际化文本const I18N = {'zh-CN': {backgroundOpenEnabled: '后台打开:开启',backgroundOpenDisabled: '后台打开:关闭'},'en-US': {backgroundOpenEnabled: 'Background Open: ON',backgroundOpenDisabled: 'Background Open: OFF'}};// 日志工具const Logger = {log: (message) => {if (GM_getValue('debugMode', false)) {console.log(`[NodeSeek脚本] ${message}`);}},error: (message) => {console.error(`[NodeSeek脚本] ${message}`);}};// 创建状态显示元素const statusElement = document.createElement('div');Object.assign(statusElement.style, CONFIG.STATUS_STYLES);document.body.appendChild(statusElement);// 获取本地化文本function getLocalizedText(key, lang = 'zh-CN') {return I18N[lang][key];}// 安全打开链接function safeOpenLink(url) {try {const sanitizedUrl = new URL(url, 'https://www.nodeseek.com').href;window.open(sanitizedUrl, '_blank', 'noopener,noreferrer');} catch (error) {Logger.error('打开链接失败: ' + error);}}// 检查后台打开是否启用function isBackgroundOpenEnabled() {return GM_getValue('backgroundOpenEnabled', CONFIG.DEFAULT_ENABLED);}// 更新状态显示function updateStatusDisplay() {const isEnabled = isBackgroundOpenEnabled();const isStatusVisible = GM_getValue('statusVisible', CONFIG.DEFAULT_STATUS_VISIBLE);statusElement.textContent = isEnabled? getLocalizedText('backgroundOpenEnabled'): getLocalizedText('backgroundOpenDisabled');statusElement.style.backgroundColor = isEnabled? 'rgba(0,128,0,0.7)': 'rgba(255,0,0,0.7)';statusElement.style.display = isStatusVisible ? 'block' : 'none';}// 切换后台打开功能function toggleBackgroundOpen() {const currentState = isBackgroundOpenEnabled();GM_setValue('backgroundOpenEnabled', !currentState);updateStatusDisplay();setupEventDelegation();}// 切换状态显示function toggleStatusVisibility() {const currentVisibility = GM_getValue('statusVisible', CONFIG.DEFAULT_STATUS_VISIBLE);GM_setValue('statusVisible', !currentVisibility);updateStatusDisplay();}// 事件委托处理链接function setupEventDelegation() {const containerSelectors = ['.thread-list','.post-list','.main-content'];containerSelectors.forEach(selector => {const container = document.querySelector(selector);if (container) {// 移除旧的事件监听器container.removeEventListener('click', handleContainerClick);// 添加新的事件监听器container.addEventListener('click', handleContainerClick);}});}// 容器点击事件处理function handleContainerClick(event) {if (!isBackgroundOpenEnabled()) return;const link = event.target.closest('a.thread-title, .thread-list-title a, .post-title a');if (link) {const href = link.getAttribute('href');if (!href) return;event.preventDefault();event.stopPropagation();safeOpenLink(href);}}// 防抖函数function debounce(func, delay) {let timeoutId;return function() {const context = this;const args = arguments;clearTimeout(timeoutId);timeoutId = setTimeout(() => func.apply(context, args), delay);};}// 注册菜单命令GM_registerMenuCommand('切换后台打开开关', toggleBackgroundOpen);GM_registerMenuCommand('切换状态显示', toggleStatusVisibility);// 状态元素点击事件statusElement.addEventListener('click', toggleBackgroundOpen);// 初始化function init() {updateStatusDisplay();setupEventDelegation();// 使用节流的 MutationObserverconst debouncedSetupEventDelegation = debounce(setupEventDelegation, CONFIG.DEBOUNCE_DELAY);const observer = new MutationObserver(debouncedSetupEventDelegation);const observerTargets = document.querySelectorAll('.thread-list, .post-list, .main-content');observerTargets.forEach(target => {observer.observe(target, {childList: true,subtree: true});});// 页面加载完成后再次处理window.addEventListener('load', setupEventDelegation);}// 启动脚本init();})();