您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
On New Reddit, makes post titles and post boxes link directly to the external website instead of the Reddit comments page.
// ==UserScript== // @name Reddit Direct Link // @namespace http://tampermonkey.net/ // @version 1.05 // @description On New Reddit, makes post titles and post boxes link directly to the external website instead of the Reddit comments page. // @author narrowstacks // @match *://www.reddit.com/* // @grant none // @license MIT // ==/UserScript== (function () { "use strict"; // List of Reddit media domains to preserve const REDDIT_MEDIA_DOMAINS = [ "i.redd.it", "v.redd.it", "preview.redd.it", "i.reddit.com", "reddit.com/gallery", ]; function isRedditMediaLink(url) { return REDDIT_MEDIA_DOMAINS.some((domain) => url.includes(domain)); } function findExternalLink(post) { // First try to find the link in the thumbnail slot as it's most reliable const thumbnailSlot = post.shadowRoot.querySelector( 'slot[name="thumbnail"]' ); if (thumbnailSlot) { const elements = thumbnailSlot.assignedElements(); for (const element of elements) { // Look for the direct link in the thumbnail area const links = element.querySelectorAll( 'a[rel="noopener nofollow ugc"]' ); for (const link of links) { // Skip if it's a Reddit media link if (isRedditMediaLink(link.href)) { return null; } if ( !link.href.includes("/comments/") && !link.href.includes("reddit.com") ) { return link; } } } } // Check content-href attribute first as it's more reliable than other slots const contentHref = post.getAttribute("content-href"); if (contentHref) { if (isRedditMediaLink(contentHref)) { return null; } if ( !contentHref.includes("/comments/") && !contentHref.includes("reddit.com") ) { return { href: contentHref }; } } // Fallback to other slots if needed const slotNames = ["title", "full-post-link", "content-href"]; for (const slotName of slotNames) { const slot = post.shadowRoot.querySelector(`slot[name="${slotName}"]`); if (!slot) continue; const elements = slot.assignedElements(); for (const element of elements) { // Check for links within the element const links = element.querySelectorAll("a"); for (const link of links) { if (isRedditMediaLink(link.href)) { continue; } if ( !link.href.includes("/comments/") && !link.href.includes("reddit.com") ) { return link; } } // Check for href attribute on the element itself if (element.href) { if (isRedditMediaLink(element.href)) { continue; } if ( !element.href.includes("/comments/") && !element.href.includes("reddit.com") ) { return element; } } } } return null; } function modifyLinks() { const posts = document.querySelectorAll( "shreddit-post:not([direct-link-processed])" ); posts.forEach((post) => { // Skip if we've already processed this post if (post.hasAttribute("direct-link-processed")) { return; } // Mark as processed immediately to prevent any race conditions post.setAttribute("direct-link-processed", "true"); // Check if post has shadowRoot if (!post.shadowRoot) { return; } // Find external link first const externalLink = findExternalLink(post); if (!externalLink) { return; } // Find and modify the full-post link const fullPostLinkSlot = post.shadowRoot.querySelector( 'slot[name="full-post-link"]' ); if (fullPostLinkSlot) { const fullPostElements = fullPostLinkSlot.assignedElements(); for (const element of fullPostElements) { if ( element.tagName === "A" && !element.hasAttribute("direct-link-processed") ) { element.setAttribute("direct-link-processed", "true"); element.href = externalLink.href; } } } // Find and modify the title link const titleSlot = post.shadowRoot.querySelector('slot[name="title"]'); if (titleSlot) { const titleElements = titleSlot.assignedElements(); for (const element of titleElements) { const titleLink = element.querySelector( "a:not([direct-link-processed])" ); if (titleLink) { titleLink.setAttribute("direct-link-processed", "true"); titleLink.href = externalLink.href; } } } }); } // Debounce function to limit how often we run modifications function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Wait for the page to be ready function init() { // Initial check modifyLinks(); // Debounce the modification function const debouncedModifyLinks = debounce(modifyLinks, 250); // Observe for dynamically loaded posts const observer = new MutationObserver((mutations) => { let shouldModify = false; for (const mutation of mutations) { if (mutation.addedNodes.length) { shouldModify = true; break; } } if (shouldModify) { debouncedModifyLinks(); } }); observer.observe(document.body, { childList: true, subtree: true, }); } // Ensure the script runs after the page is loaded if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", init); } else { init(); } })();