您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
点击帖子链接时立刻标记为已读,支持搜同和TT1069,解决快速跳转丢记录问题。
当前为
// ==UserScript== // @name Multi Forum Read Marker (Soutong + TT1069) // @namespace https://felixchristian.dev/userscripts/multi-forum-read-marker // @version 1.4.0 // @description 点击帖子链接时立刻标记为已读,支持搜同和TT1069,解决快速跳转丢记录问题。 // @author FelixChristian // @license MIT // @match https://soutong.men/forum.php?mod=forumdisplay&fid=* // @match https://soutong.men/forum.php?mod=viewthread&tid=* // @match https://www.tt1069.com/bbs/thread-*-*-*.html // @match https://www.tt1069.com/bbs/forum-*-*.html // @match https://www.tt1069.com/bbs/forum.php?mod=forumdisplay&fid=* // @match https://www.tt1069.com/bbs/forum.php?mod=forumdisplay&fid=*&* // @match https://www.tt1069.com/bbs/forum.php?mod=viewthread&tid=* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function () { 'use strict'; const STORAGE_KEY = 'visitedTids'; let visitedTids = {}; // 初始化访问记录,合并localStorage和GM存储 function loadVisited() { try { visitedTids = GM_getValue(STORAGE_KEY, {}); const localData = localStorage.getItem(STORAGE_KEY + '_temp'); if (localData) { const localObj = JSON.parse(localData); visitedTids = {...visitedTids, ...localObj}; } } catch (e) { visitedTids = {}; } } loadVisited(); function saveVisited() { try { GM_setValue(STORAGE_KEY, visitedTids); localStorage.setItem(STORAGE_KEY + '_temp', JSON.stringify(visitedTids)); } catch (e) {} } function getTidFromUrl(url) { try { const u = new URL(url, location.origin); let tid = u.searchParams.get('tid'); if (!tid) { const match = url.match(/thread-(\d+)-/); tid = match ? match[1] : null; } return tid; } catch (e) { return null; } } // 给帖子链接加已读标记 function markReadThreads() { const threadLinks = document.querySelectorAll('a.s.xst'); threadLinks.forEach(link => { if (link.dataset.markedVisited) return; // 已标记跳过 const tid = getTidFromUrl(link.href); if (tid && visitedTids[tid]) { const tag = document.createElement('span'); tag.textContent = '[已读] '; tag.style.color = 'red'; tag.style.fontWeight = 'bold'; tag.style.marginRight = '4px'; link.insertBefore(tag, link.firstChild); link.dataset.markedVisited = 'true'; } }); } // 点击帖子链接时立即标记并保存 function attachClickListeners() { const threadLinks = document.querySelectorAll('a.s.xst'); threadLinks.forEach(link => { if (link.dataset.clickListenerAdded) return; link.addEventListener('click', () => { const tid = getTidFromUrl(link.href); if (!tid) return; if (!visitedTids[tid]) { visitedTids[tid] = Date.now(); // 立即存储 saveVisited(); // 立刻显示标记 if (!link.dataset.markedVisited) { const tag = document.createElement('span'); tag.textContent = '[已读] '; tag.style.color = 'red'; tag.style.fontWeight = 'bold'; tag.style.marginRight = '4px'; link.insertBefore(tag, link.firstChild); link.dataset.markedVisited = 'true'; } } }); link.dataset.clickListenerAdded = 'true'; }); } // 页面列表页加载时标记和绑定点击事件 if (location.href.includes('mod=forumdisplay') || /forum-\d+-\d+\.html/.test(location.pathname)) { window.addEventListener('load', () => { markReadThreads(); attachClickListeners(); }); const observer = new MutationObserver(() => { markReadThreads(); attachClickListeners(); }); observer.observe(document.body, {childList: true, subtree: true}); } // 帖子详情页访问时也保存记录,防止跳转直接访问帖子时丢记录 if (location.href.includes('mod=viewthread') || /thread-\d+-/.test(location.pathname)) { const tid = getTidFromUrl(location.href); if (tid && !visitedTids[tid]) { visitedTids[tid] = Date.now(); saveVisited(); } } })();