您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Highlight new comments in a Dreamwidth comment thread
// ==UserScript== // @name Dreamwidth New Comment Highlighter // @namespace http://tampermonkey.net/ // @version 0.2 // @description Highlight new comments in a Dreamwidth comment thread // @author conroicht // @match *://*.dreamwidth.org/* // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM.getValue // @grant GM.setValue // @grant GM.deleteValue // @grant GM.listValues // @license MIT // ==/UserScript== /* jshint esversion:8 */ (function() { 'use strict'; const DEFAULT_HIGHLIGHT_BG = 'green'; const DEFAULT_HIGHLIGHT_TEXT = 'white'; const BG_KEY_NAME = 'hightlight_bg'; const TEXT_KEY_NAME = 'hightlight_text'; const BASE_KEY_NAME = 'commentHighlighter'; const STAMP_LIFE_IN_DAYS = 3; const SEARCH_KEYS = ['page', 'thread', 'view']; GM_registerMenuCommand('Set background color', async () => { const colour = prompt('Set the highlight background color'); if (colour) { await GM.setValue(BG_KEY_NAME, colour); } }); GM_registerMenuCommand('Set text color', async () => { const colour = prompt('Set highlight text color'); if (colour) { await GM.setValue(TEXT_KEY_NAME, colour); } }); async function setColorDefaults() { const background = await GM.getValue(BG_KEY_NAME); const text = await GM.getValue(TEXT_KEY_NAME); if (!background) { await GM.setValue(BG_KEY_NAME, DEFAULT_HIGHLIGHT_BG); } if (!text) { await GM.setValue(TEXT_KEY_NAME, DEFAULT_HIGHLIGHT_TEXT); } } async function clearOldStamps() { const msInOneDay = 86400000; const oldestAllowableDate = new Date() - (STAMP_LIFE_IN_DAYS * msInOneDay); const currentStoredKeys = await GM.listValues(); const stampKeys = currentStoredKeys.filter(key => key.includes(BASE_KEY_NAME)); return Promise.all(stampKeys.map(async (keyName) => { const timestamp = await GM.getValue(keyName); const date = new Date(timestamp); if (date < oldestAllowableDate) { await GM.deleteValue(keyName); } })); } function getMilitaryTime(time, period) { const [hours, minutes] = time.split(':'); const hoursAsInteger = Number.parseInt(hours, 10); if (period === 'pm' && hoursAsInteger !== 12) return `${hoursAsInteger + 12}:${minutes}`; if (period === 'am' && hoursAsInteger == 12) return `00:${minutes}`; return time; } function parseDateFromTimestamp(stamp) { const [date, time, period] = stamp.split(' '); return new Date(`${date}T${getMilitaryTime(time, period)}Z`); } function getTimestamps(rootNode = document) { return Array.from(rootNode.querySelectorAll('.comment .datetime')) .map((element) => ({ element, date: parseDateFromTimestamp(element.lastElementChild.textContent) })); } function getUrlSearchAsObject(search) { return search.replace('?', '').split('&').reduce((searches, searchString) => { const [key, value] = searchString.split('='); searches[key] = value; return searches; }, Object.create(null)); } function getThreadKey() { const { pathname, search } = window.location; const searchKeyPairs = getUrlSearchAsObject(search === '?page=1' ? '' : search); const searchStringForThreadKey = SEARCH_KEYS.reduce((keyString, key) => { if (searchKeyPairs[key]) { return `${keyString}&${key}=${searchKeyPairs[key]}`; } return keyString; }, ''); return `${BASE_KEY_NAME}${pathname}${searchStringForThreadKey}`; } function saveLastRefresh() { const now = new Date(); return GM.setValue(getThreadKey(), now.toISOString()); } async function getLastRefresh() { const lastRefreshTime = await GM.getValue(getThreadKey()); return lastRefreshTime ? new Date(lastRefreshTime) : null; } async function highlightComments(lastRefresh, rootNode = document) { const color = await GM.getValue(TEXT_KEY_NAME); const background = await GM.getValue(BG_KEY_NAME); getTimestamps(rootNode).forEach(({ element, date }) => { if (date > lastRefresh) { element.setAttribute('style', `color:${color};background:${background};`); element.textContent += ' NEW'; } }); } (async function run() { await setColorDefaults(); const lastRefresh = await getLastRefresh(); if (lastRefresh) { await highlightComments(lastRefresh); const observer = new MutationObserver((records) => { records.forEach((record) => { record.addedNodes.forEach(async (node) => { if (node.querySelector) { await highlightComments(lastRefresh, node); } }); }); }); observer.observe(document.querySelector('#comments'), { subtree: true, childList: true }); } await clearOldStamps(); await saveLastRefresh(); })(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址