您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为“今日/昨日/前日”的更新附加红/黄/绿色的文字标记,方便快速识别。只处理新加载的内容,避免重复扫描,解决 CPU 占用过高的问题。
// ==UserScript== // @name Kemono 更新標示 (彩色優化版) // @name:zh-TW Kemono 更新標示 (彩色優化版) // @name:zh-CN Kemono 更新标记 (彩色优化版) // @namespace https://greasyfork.org/users/YOUR-USER-ID // <-- 請將 YOUR-USER-ID 換成你的 Greasy Fork 用戶 ID // @version 2.0.0 // @description Highlights recent posts on Kemono with colored labels: "Today" (Red), "Yesterday" (Yellow), and "Day Before" (Green). High-performance and optimized to only process new content, fixing high CPU usage issues. // @description:zh-TW 為「今日/昨日/前日」的更新附加紅/黃/綠色的文字標示,方便快速識別。只處理新載入的內容,避免重複掃描,解決 CPU 佔用過高的問題。 // @description:zh-CN 为“今日/昨日/前日”的更新附加红/黄/绿色的文字标记,方便快速识别。只处理新加载的内容,避免重复扫描,解决 CPU 占用过高的问题。 // @author Your Name Here // <-- 請改成你的名字或暱稱 // @match https://kemono.cr/* // @match http://kemono.cr/* // @match https://kemono.su/* // @match http://kemono.su/* // @grant none // @run-at document-idle // @license MIT // ==/UserScript== (function() { 'use strict'; const prefix = '[KemonoCR]'; const log = (...args) => console.log(prefix, ...args); // --- 日期與樣式設定 --- const toYMD = (date) => { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); return `${y}-${m}-${d}`; }; const today = new Date(); const yesterday = new Date(); yesterday.setDate(today.getDate() - 1); const dayBeforeYesterday = new Date(); dayBeforeYesterday.setDate(today.getDate() - 2); // 將日期、文字和顏色映射在一起 const dateMap = { [toYMD(today)]: { text: ' 今日更新', color: 'red' }, [toYMD(yesterday)]: { text: ' 昨天更新', color: 'gold' }, // 使用 gold,比 yellow 在白色背景上更易讀 [toYMD(dayBeforeYesterday)]: { text: ' 前天更新', color: 'green' }, }; log('Date map with colors initialized:', dateMap); /** * 處理單一 <time> 元素 * @param {HTMLElement} el */ function processElement(el) { // 如果已處理過,直接跳過,這是性能優化的關鍵 if (el.dataset.kemonoProcessed) { return; } // 只取日期部分進行比對 const dateText = (el.textContent || '').trim().split(' ')[0]; const dateInfo = dateMap[dateText]; if (dateInfo) { // 創建一個新的 span 元素來包裹帶有顏色的文字 const labelSpan = document.createElement('span'); labelSpan.textContent = dateInfo.text; labelSpan.style.color = dateInfo.color; labelSpan.style.fontWeight = 'bold'; // 加粗讓文字更顯眼 // 將這個 span 附加到 <time> 元素的末尾 el.appendChild(labelSpan); log(' -> Matched & Appended:', dateText, dateInfo.text, `(Color: ${dateInfo.color})`); } // 標記為已處理,避免重複執行 el.dataset.kemonoProcessed = 'true'; } /** * 在指定的節點內尋找並處理所有未處理的 <time.timestamp> 元素 * @param {Node} targetNode */ function findAndProcessInNode(targetNode) { if (targetNode.nodeType !== Node.ELEMENT_NODE) { return; } // 使用 :not 選擇器,高效地跳過已處理的元素 const elements = targetNode.querySelectorAll('time.timestamp:not([data-kemono-processed])'); if (elements.length > 0) { log(`Found ${elements.length} new element(s) to process.`); elements.forEach(processElement); } } // --- 腳本主邏輯 --- // 1. 頁面初次載入時,處理所有現存的元素 log('Initial page scan...'); findAndProcessInNode(document.body); log('Initial scan complete.'); // 2. 設定 MutationObserver 來監控後續動態加入的內容 const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { // 只對新增加的節點進行掃描,效率極高 mutation.addedNodes.forEach(node => { findAndProcessInNode(node); }); } } }); // 開始監聽 document.body 的子節點變化 observer.observe(document.body, { childList: true, // 只關心子節點的增加或刪除 subtree: true // 監聽所有後代節點 }); })();