// ==UserScript== // @name NodeSeek 全部已读增强版 // @namespace http://tampermonkey.net/ // @version 0.3 // @description 一键标记 NodeSeek 所有通知为已读,支持自定义功能。功能包括:三页全部已读、无弹窗提示、禁用原有功能等 // @author wzsxh // @match https://www.nodeseek.com/notification* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @license MIT // @supportURL https://www.nodeseek.com/space/9074#/general // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 默认设置 const defaultSettings = { enableTripleRead: true, // 启用三页全部已读 enableNoPrompt: true, // 启用原有已读功能不弹窗 disableOriginal: false // 禁用原有已读功能 }; // 获取设置 let settings = Object.assign({}, defaultSettings, GM_getValue('nodeseek_settings', {})); // 注册菜单命令 function registerMenuCommands() { GM_registerMenuCommand(`${settings.enableTripleRead ? '✅' : '❌'} 三页全部已读功能`, () => { settings.enableTripleRead = !settings.enableTripleRead; GM_setValue('nodeseek_settings', settings); location.reload(); }); GM_registerMenuCommand(`${settings.enableNoPrompt ? '✅' : '❌'} 原有已读功能不弹窗`, () => { settings.enableNoPrompt = !settings.enableNoPrompt; GM_setValue('nodeseek_settings', settings); location.reload(); }); GM_registerMenuCommand(`${settings.disableOriginal ? '✅' : '❌'} 禁用原有已读功能`, () => { settings.disableOriginal = !settings.disableOriginal; GM_setValue('nodeseek_settings', settings); location.reload(); }); } window.addEventListener('load', () => { // 注册菜单 registerMenuCommands(); // API URL配置 const apiUrls = { 'atMe': 'https://www.nodeseek.com/api/notification/at-me/markViewed?all=true', 'reply': 'https://www.nodeseek.com/api/notification/reply-to-me/markViewed?all=true', 'message': 'https://www.nodeseek.com/api/notification/message/markViewed?all=true' }; // 创建统一的标记已读函数 async function markAsRead(button, originalText, urls, removeAllUnread = true) { const originalBgColor = button.style.backgroundColor; try { button.innerHTML = '处理中...'; button.style.backgroundColor = '#52c41a'; const responses = await Promise.all(urls.map(url => fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' } }).then(res => res.json()) )); const allSuccess = responses.every(res => res.success === true); if (allSuccess) { button.innerHTML = '已完成'; const listItems = document.querySelectorAll('.ant-list-item'); listItems.forEach(item => item.style.display = 'none'); // 移除全部未读数字 if (removeAllUnread) { const unreadCounts = document.querySelectorAll('span.unread-count'); unreadCounts.forEach(unreadCount => unreadCount.remove()); } else { // 移除当前页面的未读数字 const hash = window.location.hash; let currentSpan; if (hash.includes('/atMe')) { currentSpan = `a[href="#/atMe"] span.unread-count`; } else if (hash.includes('/reply')) { currentSpan = `a[href="#/reply"] span.unread-count`; } else if (hash.includes('/message')) { currentSpan = `a[href="#/message"] span.unread-count`; } const currentPageUnreadCount = document.querySelector(currentSpan); if (currentPageUnreadCount) { currentPageUnreadCount.remove(); } } } else { throw new Error('部分请求失败'); } } catch (error) { console.error('标记已读失败:', error); button.innerHTML = '失败'; button.style.backgroundColor = '#ff4d4f'; } finally { setTimeout(() => { button.innerHTML = originalText; button.style.backgroundColor = originalBgColor; }, 1000); } } // 仅在启用三页全部已读功能时创建按钮 if (settings.enableTripleRead) { const button = document.createElement('button'); const buttonText = '三页全部已读'; button.innerHTML = buttonText; button.style.cssText = ` margin: 0 20px; padding: 6px 12px; background-color: #1890ff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 900; transition: all 0.3s; `; button.addEventListener('mouseenter', () => { button.style.backgroundColor = '#40a9ff'; }); button.addEventListener('mouseleave', () => { button.style.backgroundColor = '#1890ff'; }); button.addEventListener('click', () => { const urls = Object.values(apiUrls); markAsRead(button, buttonText, urls); }); const appSwitch = document.querySelector('.app-switch'); if (appSwitch) { appSwitch.appendChild(button); } } // 处理原有的单个已读按钮 function handleOriginalButtons() { const originalReadButtons = document.querySelectorAll('button.btn'); originalReadButtons.forEach(btn => { if (btn.textContent.includes('全部标为已读')) { if (settings.disableOriginal) { btn.style.display = 'none'; return; } if (settings.enableNoPrompt) { const newBtn = btn.cloneNode(true); newBtn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const hash = window.location.hash; let apiUrl; if (hash.includes('/atMe')) { apiUrl = apiUrls.atMe; } else if (hash.includes('/reply')) { apiUrl = apiUrls.reply; } else if (hash.includes('/message')) { apiUrl = apiUrls.message; } if (apiUrl) { markAsRead(newBtn, newBtn.textContent, [apiUrl], false); // 传递 false 以移除当前页面的未读数字 } }); btn.replaceWith(newBtn); } } }); } function checkAndHandleButtons() { const checkInterval = setInterval(() => { const buttons = document.querySelectorAll('button.btn'); if (buttons.length > 0) { handleOriginalButtons(); clearInterval(checkInterval); } }, 500); setTimeout(() => clearInterval(checkInterval), 30000); } let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; setTimeout(checkAndHandleButtons, 100); } }).observe(document, {subtree: true, childList: true}); checkAndHandleButtons(); }); })();