Hide posts or comments containing specific keywords, by users, or comment authors, with toggle and settings popup
// ==UserScript==
// @name Reddit Post Filter
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Hide posts or comments containing specific keywords, by users, or comment authors, with toggle and settings popup
// @author brfuk
// @license MIT
// @match *://www.reddit.com/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// Retrieve stored values
let blockedKeywords = GM_getValue('blockedKeywords', ["test"]);
let blockedUsers = GM_getValue('blockedUsers', ["test"]);
let blockedCommenters = GM_getValue('blockedCommenters', ["test"]);
let filterEnabled = GM_getValue('filterEnabled', true);
// Add styles
const style = `
#popup-container {
display: none;
position: fixed;
top: 10%;
left: 50%;
transform: translateX(-50%);
background-color: white;
border: 1px solid #ccc;
padding: 10px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
z-index: 9999;
width: 300px;
height: 500px;
overflow: auto;
}
#popup-container h2 {
text-align: center;
}
#popup-container label {
display: block;
margin-top: 5px;
}
#popup-container textarea {
width: 100%;
height: 95px;
margin-top: 1px;
}
#popup-container button {
display: block;
width: 100%;
margin-top: 1px;
padding: 1px 1px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
}
#popup-container button:hover {
background-color: #45a049;
}
#open-popup-button {
position: fixed;
bottom: 10px;
right: 10px;
background-color: #4CAF50;
color: white;
border: none;
padding: 5px 5px;
cursor: pointer;
font-size: 14px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
transition: background-color 0.3s;
display: flex;
align-items: center;
justify-content: center;
}
#open-popup-button:hover {
background-color: #45a049;
}
`;
const popupContainer = document.createElement('div');
popupContainer.id = 'popup-container';
popupContainer.style.display = 'none';
popupContainer.innerHTML = `
<h2>Modify Keywords and Users</h2>
<label for="enableFilter">
<input type="checkbox" id="enableFilter" ${filterEnabled ? "checked" : ""}>
Enable Filtering
</label>
<label for="keywords">Keywords:</label>
<textarea id="keywords">${blockedKeywords.join("\n")}</textarea>
<label for="users">Post Authors:</label>
<textarea id="users">${blockedUsers.join("\n")}</textarea>
<label for="commenters">Comment Authors:</label>
<textarea id="commenters">${blockedCommenters.join("\n")}</textarea>
<button id="save-button">Save</button>
`;
document.body.appendChild(popupContainer);
const styleTag = document.createElement('style');
styleTag.innerHTML = style;
document.head.appendChild(styleTag);
const openButton = document.createElement('button');
openButton.id = 'open-popup-button';
openButton.innerText = '⚙️';
document.body.appendChild(openButton);
openButton.addEventListener('click', () => {
popupContainer.style.display = 'block';
});
document.getElementById('save-button').addEventListener('click', () => {
const updatedKeywords = document.getElementById('keywords').value.split("\n").filter(k => k.trim() !== "");
const updatedUsers = document.getElementById('users').value.split("\n").filter(u => u.trim() !== "");
const updatedCommenters = document.getElementById('commenters').value.split("\n").filter(c => c.trim() !== "");
const enableFilter = document.getElementById('enableFilter').checked;
GM_setValue('blockedKeywords', updatedKeywords);
GM_setValue('blockedUsers', updatedUsers);
GM_setValue('blockedCommenters', updatedCommenters);
GM_setValue('filterEnabled', enableFilter);
blockedKeywords = updatedKeywords;
blockedUsers = updatedUsers;
blockedCommenters = updatedCommenters;
filterEnabled = enableFilter;
popupContainer.style.display = 'none';
hideBlockedPosts();
hideBlockedComments();
});
window.addEventListener('keydown', (event) => {
if (event.ctrlKey && event.key === 'z') {
popupContainer.style.display = 'block';
}
});
// window.addEventListener('keydown', (event) => {
// if (event.key === 'Escape') {
// popupContainer.style.display = 'none';
// }
// });
let escInterceptor = (event) => {
if (event.key === 'Escape') {
event.stopImmediatePropagation();
event.preventDefault();
popupContainer.style.display = 'none';
window.removeEventListener('keydown', escInterceptor, true); // ✅ 弹窗关闭后移除拦截器
}
};
window.addEventListener('keydown', (event) => {
if (event.ctrlKey && event.key === 'z') {
popupContainer.style.display = 'block';
window.addEventListener('keydown', escInterceptor, true); // ✅ 弹窗打开时添加拦截器
}
});
openButton.addEventListener('click', () => {
popupContainer.style.display = 'block';
window.addEventListener('keydown', escInterceptor, true); // ✅ 弹窗打开时添加拦截器
});
function hideBlockedPosts() {
if (!filterEnabled) return;
let posts = document.querySelectorAll('shreddit-post');
posts.forEach(post => {
let titleElem = post.querySelector('[id^="post-title"]');
if (!titleElem) return;
let titleText = titleElem.innerText.toLowerCase();
let authorName = post.getAttribute('author');
if (blockedKeywords.some(keyword => titleText.includes(keyword.toLowerCase()))) {
console.log(`🔕 Post blocked - Keyword match`);
post.style.display = 'none';
return;
}
if (blockedUsers.includes(authorName)) {
console.log(`🔕 Post blocked - Author: ${authorName}`);
post.style.display = 'none';
}
});
}
function hideBlockedComments() {
if (!filterEnabled) return;
const comments = document.querySelectorAll('shreddit-comment');
comments.forEach(comment => {
const commenterName = comment.getAttribute('author');
if (!commenterName) return;
if (blockedCommenters.includes(commenterName)) {
console.log(`💬 Comment blocked - Author: ${commenterName}`);
comment.style.display = 'none';
}
});
}
hideBlockedPosts();
hideBlockedComments();
const observer = new MutationObserver(() => {
hideBlockedPosts();
hideBlockedComments();
});
observer.observe(document.body, { childList: true, subtree: true });
})();