您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Preview links and show their titles with caching for 3 days
// ==UserScript== // @name PreviewLinks // @namespace https://jirehlov.com // @version 0.2.8 // @description Preview links and show their titles with caching for 3 days // @author Jirehlov // @include /^https?://(bangumi\.tv|bgm\.tv|chii\.in)/.* // @grant none // @license MIT // ==/UserScript== (function () { "use strict"; const CACHE_PREFIX = "PLinksCache_"; const CACHE_EXPIRATION = 7 * 24 * 60 * 60 * 1000; const getTitleFromLink = async link => { const linkURL = link.href; const cachedTitle = getCachedTitle(linkURL); if (cachedTitle !== null) { return cachedTitle; } try { let title = ""; if (link.textContent === link.href) { const response = await fetch(linkURL); const data = await response.text(); const parser = new DOMParser(); const htmlDoc = parser.parseFromString(data, "text/html"); const titleElement = htmlDoc.querySelector("h1.nameSingle a"); const blogTitleElement = htmlDoc.querySelector("h1"); const epTitleElement = htmlDoc.querySelector("h2.title"); title = titleElement ? titleElement.textContent : ""; const chineseName = titleElement ? titleElement.getAttribute("title") : ""; if (chineseName && (link.href.includes("subject") || link.href.includes("ep"))) { title += title ? ` | ${ chineseName }` : chineseName; } if (link.href.includes("ep") && epTitleElement) { epTitleElement.querySelectorAll("small").forEach(small => small.remove()); const epTitle = epTitleElement.textContent.trim(); title += title ? ` | ${ epTitle }` : epTitle; } if ((link.href.includes("blog") || link.href.includes("topic") || link.href.includes("index")) && blogTitleElement) { title = blogTitleElement.textContent.trim(); } const prefix = link.href.match(/\/(subject\/topic|subject|ep|character|person|blog|group\/topic|index)\/[^/]+/); const prefixText = prefix ? `[${ prefix[1] }] ` : ""; title = prefixText + title; cacheTitle(linkURL, title); return title; } else { return null; } } catch (error) { console.error("Error fetching data:", error); return null; } }; const cacheTitle = (url, title) => { const cacheKey = CACHE_PREFIX + url; const cacheValue = { title: title, timestamp: Date.now() }; localStorage.setItem(cacheKey, JSON.stringify(cacheValue)); }; const getCachedTitle = url => { const cacheKey = CACHE_PREFIX + url; const cacheValue = localStorage.getItem(cacheKey); if (cacheValue !== null) { const {title, timestamp} = JSON.parse(cacheValue); if (Date.now() - timestamp < CACHE_EXPIRATION) { return title; } else { localStorage.removeItem(cacheKey); } } return null; }; const domains = [ "bgm.tv", "chii.in", "bangumi.tv" ]; const paths = [ "subject/", "ep/", "character/", "person/", "blog/", "group/topic/", "index/" ]; const selectors = []; domains.forEach(domain => { paths.forEach(path => { selectors.push(`a[href^="https://${ domain }/${ path }"]`); }); }); const allLinks = document.querySelectorAll(selectors.join(",")); const fetchAndReplaceLinkText = () => { let index = 0; const processNextLink = async () => { if (index < allLinks.length) { const link = allLinks[index]; const cachedTitle = getCachedTitle(link.href); if (link.textContent === link.href) { if (cachedTitle) { link.textContent = cachedTitle; } else { const title = await getTitleFromLink(link); if (title) { link.textContent = title; } setTimeout(processNextLink, 3000); return; } } index++; processNextLink(); } }; processNextLink(); }; fetchAndReplaceLinkText(); }());