您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Highlight new comments in a Dreamwidth comment thread
当前为
// ==UserScript== // @name Dreamwidth New Comment Highlighter // @namespace http://tampermonkey.net/ // @version 0.1 // @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'; GM_registerMenuCommand('Highlight background', async () => { const colour = prompt('Set highlight background colour'); if (colour) { await GM.setValue('highlight_bg', colour); } }); GM_registerMenuCommand('Highlight text colour', async () => { const colour = prompt('Set highlight text colour'); if (colour) { await GM.setValue('highlight_text', colour); } }); const HIGHLIGHT_BG = 'green'; const HIGHLIGHT_TEXT = 'white'; const BASE_KEY_NAME = 'commentHighlighter'; const STAMP_LIFE_IN_DAYS = 3; const searchKeys = ['page', 'thread', 'view']; 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 = searchKeys.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('highlight_text'); const background = await GM.getValue('highlight_bg'); getTimestamps(rootNode).forEach(({ element, date }) => { if (date > lastRefresh) { element.setAttribute('style', `color:${color};background:${background};`) element.textContent += ' NEW'; } }); } (async function run() { 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(); GM.setValue('highlight_bg', await GM.getValue('highlight_bg') || HIGHLIGHT_BG); GM.setValue('highlight_text', await GM.getValue('highlight_text') || HIGHLIGHT_TEXT); })(); })();