Adds one button to hide all currently loaded Reddit feed posts.
// ==UserScript==
// @name Reddit Hide Loaded Posts
// @namespace floris.webpatches
// @version 1.0.0
// @description Adds one button to hide all currently loaded Reddit feed posts.
// @author Floris
// @match https://www.reddit.com/*
// @run-at document-idle
// @grant none
// @license MIT
// ==/UserScript==
(() => {
"use strict";
const BUTTON_ID = "floris-hide-loaded-posts";
const DELAY_MS = 1500;
let busy = false;
let updateTimer = null;
const sleep = ms =>
new Promise(resolve => setTimeout(resolve, ms));
function getPosts() {
if (location.pathname.includes("/comments/")) {
return [];
}
return [...document.querySelectorAll("shreddit-post")]
.filter(post => {
if (post.offsetParent === null) return false;
if (post.closest("shreddit-ad-post")) return false;
if (post.matches('[data-shreddit-promoted="true"]')) return false;
const menu = post.querySelector(
"shreddit-post-overflow-menu"
);
if (!menu) return false;
const actions = menu.overflowActions;
if (Array.isArray(actions)) {
return actions.some(
action => action?.id === "hide"
);
}
return true;
});
}
async function hideThroughComponent(post) {
const menu = post.querySelector(
"shreddit-post-overflow-menu"
);
if (!menu) return false;
const actions = menu.overflowActions;
if (!Array.isArray(actions)) return false;
const hideAction = actions.find(
action => action?.id === "hide"
);
if (
!hideAction ||
typeof hideAction.onClick !== "function"
) {
return false;
}
try {
await hideAction.onClick();
return true;
} catch {
return false;
}
}
async function hideThroughMenu(post) {
const menu = post.querySelector(
"shreddit-post-overflow-menu"
);
if (!menu) return false;
const trigger =
menu.querySelector("button") ||
menu.shadowRoot?.querySelector("button");
if (!trigger) return false;
trigger.click();
await sleep(300);
const candidates = [
...document.querySelectorAll(
'button, a, [role="menuitem"], li'
)
];
const hideItem = candidates.find(element => {
const text =
element.textContent?.trim().toLowerCase();
return (
text === "hide" ||
text === "verbergen" ||
text === "post verbergen"
);
});
if (!hideItem) {
document.body.click();
return false;
}
hideItem.click();
return true;
}
async function hidePost(post) {
let ok = await hideThroughComponent(post);
if (!ok) {
ok = await hideThroughMenu(post);
}
return ok;
}
function getButton() {
return document.getElementById(BUTTON_ID);
}
function setButtonText(text) {
const button = getButton();
if (button) {
button.textContent = text;
}
}
function updateButton() {
if (busy) return;
const button = getButton();
if (!button) return;
const count = getPosts().length;
button.disabled = count === 0;
button.textContent =
count === 0
? "No loaded posts"
: `Hide ${count} loaded post${count === 1 ? "" : "s"}`;
}
function scheduleUpdate() {
clearTimeout(updateTimer);
updateTimer = setTimeout(
updateButton,
350
);
}
async function hideLoadedPosts() {
if (busy) return;
const posts = getPosts();
if (!posts.length) {
updateButton();
return;
}
busy = true;
const button = getButton();
button.disabled = true;
let hidden = 0;
let failed = 0;
for (let i = 0; i < posts.length; i++) {
setButtonText(
`Hiding ${i + 1}/${posts.length} · ${hidden} hidden`
);
const ok = await hidePost(posts[i]);
if (ok) {
hidden++;
} else {
failed++;
}
if (i < posts.length - 1) {
await sleep(DELAY_MS);
}
}
setButtonText(
failed
? `Done · ${hidden} hidden · ${failed} failed`
: `Done · ${hidden} hidden`
);
busy = false;
button.disabled = false;
setTimeout(
updateButton,
1800
);
}
function createButton() {
if (getButton()) return;
const button =
document.createElement("button");
button.id = BUTTON_ID;
button.type = "button";
button.textContent = "Hide loaded posts";
Object.assign(button.style, {
position: "fixed",
right: "24px",
bottom: "82px",
zIndex: "2147483647",
display: "flex",
alignItems: "center",
justifyContent: "center",
minWidth: "148px",
height: "38px",
padding: "0 16px",
boxSizing: "border-box",
border: "1px solid rgba(255,255,255,.18)",
borderRadius: "999px",
background: "rgba(20,20,22,.96)",
color: "#ffffff",
fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
fontSize: "13px",
fontWeight: "600",
lineHeight: "1",
whiteSpace: "nowrap",
textAlign: "center",
boxShadow: "0 6px 24px rgba(0,0,0,.28)",
cursor: "pointer"
});
button.addEventListener(
"click",
hideLoadedPosts
);
document.body.appendChild(button);
updateButton();
}
createButton();
addEventListener(
"scroll",
scheduleUpdate,
{ passive: true }
);
addEventListener(
"popstate",
scheduleUpdate
);
document.addEventListener(
"visibilitychange",
() => {
if (!document.hidden) {
scheduleUpdate();
}
}
);
setInterval(() => {
if (!busy) {
updateButton();
}
}, 5000);
})();