您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds post authors to items in Reddit feed (on new Reddit)
// ==UserScript== // @name Creddit // @namespace github.com/JasonAMelancon // @version 2025-09-03 // @description Adds post authors to items in Reddit feed (on new Reddit) // @author Jason Melancon // @license GNU AGPLv3 // @match http*://www.reddit.com/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // ==/UserScript== (function() { 'use strict'; //-- script begins here --// const DEBUG = false; // The msg is in a lambda expression body so that string interpolation only happens if we // actually print the message (lazy evaluation). function debugLog(lambdifiedMsg) { if (DEBUG) console.log(lambdifiedMsg()); } const scriptName = GM_info.script.name; //== This is the main part of the script. ==// function runScript() { const CREDITED = "is-credited"; // my custom attribute for the post element const POST = "shreddit-post"; // Reddit's custom element name const FEED = "shreddit-feed"; // Reddit's custom element name const feeds = document.getElementsByTagName(FEED); if (feeds.length > 1) { // I have no idea whether this is or will ever be necessary console.log(`[${scriptName}] Multiple Reddit feed nodes present`); } const feed = feeds[0]; debugLog(() => `[${scriptName}] ${feed.querySelectorAll("article").length} initial articles`); // Get the first few articles in the feed when the page loads, and add the author. feed.querySelectorAll("article").forEach(article => { if (!isCredited(article)) { creditAuthor(article); markCredited(article); } }); // Watch the page for new articles that appear when scrolling. const dynamicScroll = new MutationObserver(mutations => { debugLog(() => `[${scriptName}] ${mutations.length} new mutation objects`); for (let mutation of mutations) { const newArticleArray = Array.from(mutation.addedNodes).filter(node => node.nodeName === "ARTICLE"); debugLog(() => `[${scriptName}] ${newArticleArray.length} new articles`); if (newArticleArray.length == 0) continue; // Add the author to the new articles as they appear. newArticleArray.forEach(article => { if (!isCredited(article)) { creditAuthor(article); markCredited(article); } }); } }); dynamicScroll.observe(feed, { childList: true, subtree: false, attributes: false, characterData: false }); // Put the author of a single article on the top line, next to the subreddit and post age. function creditAuthor(article) { const post = article.querySelector(POST); const creditBar = post.querySelector("[id*='credit-bar']"); const separator = creditBar.querySelector(".created-separator"); creditBar.appendChild(separator.cloneNode(/*deep = */true)); const byLineClass = separator.nextElementSibling.getAttribute("class"); const byLine = document.createElement("span"); creditBar.appendChild(byLine).setAttribute("class", byLineClass); const author = post.getAttribute("author"); if (author === "[deleted]") { byLine.innerHTML = `by ${author}`; } else { byLine.innerHTML = `by <a href="/u/${author}">${author}</a>`; } } // When scrolling down far enough, Reddit unloads posts from the top of the page, // presumably to save memory. In general, Reddit unloads posts you scroll away from // and loads or reloads posts you scroll toward. Without checking to make sure the // post hasn't already been credited, this can cause this script to credit the post // multiple times when the MutationObserver notices a credited post reappear in the // feed. // // Therefore, check first. function isCredited(article) { const post = article.querySelector(POST); debugLog(() => `[${scriptName}] credited check: ${post.hasAttribute(CREDITED)}`); return post.hasAttribute(CREDITED); } // Marks a post as already credited. function markCredited(article) { const post = article.querySelector(POST); post.setAttribute(CREDITED, ""); } } //== This is the part of the script that deals with the PITA way Reddit does scripted navigation. ==// // Specify known titles for feed pages, because the script should work even when the user // types in a URL that *isn't* a feed page, and then uses the site's own navigation interface // to go to one. const redditFeedTitles = { home : "Reddit - The heart of the internet", popular : "r/popular" }; // Detect feed page on initial load by checking the path. This script is primarily designed to run // on the home page, since that's where the feed is, but on further reflection, it can also run on // r/popular, because that's basically a feed too; it's not really a subreddit. if ([ "/", "/r/popular/" ].includes(window.location.pathname)) { // limited future-proofing in case Reddit changes their title if (window.location.pathname == "/") { redditFeedTitles.home = document.title; } else { redditFeedTitles.popular = document.title; } runScript(); } // Run the script when using the nav bar (fake AJAX navigation) to get to the feed. new MutationObserver(() => { if (Object.values(redditFeedTitles).includes(document.title)) { runScript(); } }).observe(document.querySelector("title"), { childList: true }); //-- script ends here --// })();