Advertisement
popstick

hide-posts-1.2.13.js

Feb 5th, 2025 (edited)
15
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.02 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Hide Posts & Comments by Keywords with UI on Reddit (Universal)
  3. // @namespace https://naroman.tl
  4. // @version 1.2.13-custom-colours
  5. // @description Hide posts and comments containing specified keywords on both new and old Reddit interfaces. A small purple circle opens a modal to update keywords. Works on both reddit.com and old.reddit.com.
  6. // @author
  7. // @match *://*.reddit.com/*
  8. // @match *://old.reddit.com/*
  9. // @grant none
  10. // @updateURL https://naroman.tl/wp-content/hidepost/hide-posts.js
  11. // @downloadURL https://naroman.tl/wp-content/hidepost/hide-posts.js
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. // Load keywords from localStorage (or use defaults)
  18. let postKeywords = JSON.parse(localStorage.getItem("redditPostKeywords") || '["musk", "elon", "biden"]');
  19. let commentKeywords = JSON.parse(localStorage.getItem("redditCommentKeywords") || '["hawk tuah"]');
  20.  
  21. // Returns true if the provided text contains any of the keywords (case-insensitive)
  22. function containsKeyword(text, keywords) {
  23. return keywords.some(keyword => text.toLowerCase().includes(keyword.toLowerCase()));
  24. }
  25.  
  26. // Helper: Get visible text from an element.
  27. // Prefer innerText (which better reflects what the user sees); fallback to textContent.
  28. function getVisibleText(el) {
  29. return el.innerText || el.textContent || "";
  30. }
  31.  
  32. // Main filtering function – hides posts and comments whose visible text includes a keyword.
  33. function hideContent() {
  34. console.log("hideContent() called");
  35.  
  36. if (window.location.hostname.includes("old.reddit.com")) {
  37. // -------- OLD REDDIT --------
  38. // Old Reddit posts: select .thing elements that do NOT also have the class "comment"
  39. const oldPosts = document.querySelectorAll('.thing:not(.comment):not([data-checked])');
  40. console.log("Old posts found: " + oldPosts.length);
  41. oldPosts.forEach(post => {
  42. const title = post.querySelector('a.title');
  43. if (title && containsKeyword(getVisibleText(title), postKeywords)) {
  44. post.style.display = 'none';
  45. console.log("Hiding OLD post: " + getVisibleText(title));
  46. }
  47. post.setAttribute('data-checked', 'true');
  48. });
  49.  
  50. // Old Reddit comments: select .thing.comment elements
  51. const oldComments = document.querySelectorAll('.thing.comment:not([data-checked])');
  52. console.log("Old comments found: " + oldComments.length);
  53. oldComments.forEach(comment => {
  54. // The comment text is usually inside a descendant with class "usertext-body"
  55. const textElement = comment.querySelector('.usertext-body');
  56. if (textElement && containsKeyword(getVisibleText(textElement), commentKeywords)) {
  57. comment.style.display = 'none';
  58. console.log("Hiding OLD comment: " + getVisibleText(textElement).substring(0,50));
  59. }
  60. comment.setAttribute('data-checked', 'true');
  61. });
  62. } else {
  63. // -------- NEW REDDIT --------
  64. // New posts: select using data-testid or <shreddit-post>
  65. const newPosts = document.querySelectorAll(
  66. 'div[data-testid="post-container"]:not([data-checked]), shreddit-post:not([data-checked])'
  67. );
  68. console.log("New posts found: " + newPosts.length);
  69. newPosts.forEach(post => {
  70. const title = post.querySelector('h3, a[slot="title"]');
  71. if (title && containsKeyword(getVisibleText(title), postKeywords)) {
  72. post.style.display = 'none';
  73. console.log("Hiding NEW post: " + getVisibleText(title));
  74. }
  75. post.setAttribute('data-checked', 'true');
  76. });
  77.  
  78. // New comments: try selector for div elements with id starting with "t1_"
  79. const newComments = document.querySelectorAll('div[id^="t1_"]:not([data-checked])');
  80. console.log("New comments found (div[id^='t1_']): " + newComments.length);
  81. newComments.forEach(comment => {
  82. const text = getVisibleText(comment);
  83. if (containsKeyword(text, commentKeywords)) {
  84. comment.style.display = 'none';
  85. console.log("Hiding NEW comment (t1_): " + text.substring(0,50));
  86. }
  87. comment.setAttribute('data-checked', 'true');
  88. });
  89. // Also try alternative selectors
  90. const newCommentsAlt = document.querySelectorAll(
  91. 'div[data-testid="comment"]:not([data-checked]), shreddit-comment:not([data-checked]), reddit-comment:not([data-checked])'
  92. );
  93. console.log("New comments found (alt selectors): " + newCommentsAlt.length);
  94. newCommentsAlt.forEach(comment => {
  95. const text = getVisibleText(comment);
  96. if (containsKeyword(text, commentKeywords)) {
  97. comment.style.display = 'none';
  98. console.log("Hiding NEW comment (alt): " + text.substring(0,50));
  99. }
  100. comment.setAttribute('data-checked', 'true');
  101. });
  102. }
  103. }
  104.  
  105. // Set up a MutationObserver to catch new nodes (e.g. infinite scrolling)
  106. const observer = new MutationObserver(mutations => {
  107. mutations.forEach(mutation => {
  108. if (mutation.addedNodes.length > 0) {
  109. console.log("MutationObserver: " + mutation.addedNodes.length + " node(s) added");
  110. hideContent();
  111. }
  112. });
  113. });
  114. observer.observe(document.body, { childList: true, subtree: true });
  115.  
  116. // Also run hideContent() on window load
  117. window.addEventListener('load', () => {
  118. console.log("Window load event fired");
  119. hideContent();
  120. });
  121.  
  122. // Periodic filtering: run hideContent() every 1 second for up to 60 seconds.
  123. let attempts = 0;
  124. const maxAttempts = 60;
  125. const intervalId = setInterval(() => {
  126. console.log("Interval attempt " + attempts);
  127. hideContent();
  128. attempts++;
  129. if (attempts >= maxAttempts) {
  130. clearInterval(intervalId);
  131. console.log("Cleared interval after " + attempts + " attempts");
  132. }
  133. }, 1000);
  134.  
  135. // --- UI: Create a modal for updating keywords with updated colour scheme ---
  136. function createKeywordUI() {
  137. // Create the floating button (now using #9232E4)
  138. const button = document.createElement("button");
  139. button.innerText = "";
  140. button.title = "Keywords";
  141. button.id = "keywordsButton";
  142. button.style.position = "fixed";
  143. button.style.top = "10px";
  144. button.style.right = "10px";
  145. button.style.zIndex = "9999";
  146. button.style.width = "20px";
  147. button.style.height = "20px";
  148. button.style.backgroundColor = "#9232E4"; // purple accent
  149. button.style.border = "none";
  150. button.style.borderRadius = "50%";
  151. button.style.cursor = "pointer";
  152. button.style.boxShadow = "0 0 3px rgba(0,0,0,0.3)";
  153. document.body.appendChild(button);
  154.  
  155. // Create the modal overlay with a semi-transparent #0C1824 background.
  156. const modal = document.createElement("div");
  157. modal.id = "keywordsModal";
  158. modal.style.display = "none";
  159. modal.style.position = "fixed";
  160. modal.style.top = "0";
  161. modal.style.left = "0";
  162. modal.style.width = "100%";
  163. modal.style.height = "100%";
  164. modal.style.backgroundColor = "rgba(12, 24, 36, 0.8)"; // dark, using #0C1824
  165. modal.style.zIndex = "10000";
  166. modal.style.backdropFilter = "blur(5px)";
  167.  
  168. // Modal content container
  169. const modalContent = document.createElement("div");
  170. modalContent.style.position = "absolute";
  171. modalContent.style.top = "50%";
  172. modalContent.style.left = "50%";
  173. modalContent.style.transform = "translate(-50%, -50%)";
  174. modalContent.style.backgroundColor = "#FFFFFF";
  175. modalContent.style.padding = "20px";
  176. modalContent.style.borderRadius = "8px";
  177. modalContent.style.boxShadow = "0 4px 15px rgba(0,0,0,0.2)";
  178. modalContent.style.maxWidth = "90%";
  179. modalContent.style.width = "320px";
  180. modalContent.style.fontFamily = "Arial, sans-serif";
  181.  
  182. // Modal title (using #9232E4 as accent)
  183. const modalTitle = document.createElement("h3");
  184. modalTitle.innerText = "Set Keywords";
  185. modalTitle.style.marginBottom = "15px";
  186. modalTitle.style.fontSize = "18px";
  187. modalTitle.style.color = "#9232E4";
  188. modalContent.appendChild(modalTitle);
  189.  
  190. // Input for Post Keywords
  191. const postLabel = document.createElement("label");
  192. postLabel.innerText = "Post Keywords:";
  193. postLabel.style.display = "block";
  194. postLabel.style.marginBottom = "5px";
  195. postLabel.style.fontSize = "14px";
  196. postLabel.style.fontWeight = "bold";
  197. modalContent.appendChild(postLabel);
  198.  
  199. const postInput = document.createElement("input");
  200. postInput.type = "text";
  201. postInput.id = "postKeywordsInput";
  202. postInput.style.width = "100%";
  203. postInput.style.padding = "8px";
  204. postInput.style.marginBottom = "15px";
  205. postInput.style.border = "1px solid #ccc";
  206. postInput.style.borderRadius = "4px";
  207. postInput.style.fontSize = "14px";
  208. postInput.value = postKeywords.join(", ");
  209. modalContent.appendChild(postInput);
  210.  
  211. // Input for Comment Keywords
  212. const commentLabel = document.createElement("label");
  213. commentLabel.innerText = "Comment Keywords:";
  214. commentLabel.style.display = "block";
  215. commentLabel.style.marginBottom = "5px";
  216. commentLabel.style.fontSize = "14px";
  217. commentLabel.style.fontWeight = "bold";
  218. modalContent.appendChild(commentLabel);
  219.  
  220. const commentInput = document.createElement("input");
  221. commentInput.type = "text";
  222. commentInput.id = "commentKeywordsInput";
  223. commentInput.style.width = "100%";
  224. commentInput.style.padding = "8px";
  225. commentInput.style.marginBottom = "15px";
  226. commentInput.style.border = "1px solid #ccc";
  227. commentInput.style.borderRadius = "4px";
  228. commentInput.style.fontSize = "14px";
  229. commentInput.value = commentKeywords.join(", ");
  230. modalContent.appendChild(commentInput);
  231.  
  232. // Buttons container
  233. const buttonsContainer = document.createElement("div");
  234. buttonsContainer.style.display = "flex";
  235. buttonsContainer.style.justifyContent = "flex-end";
  236. buttonsContainer.style.marginTop = "10px";
  237.  
  238. // Save button
  239. const saveButton = document.createElement("button");
  240. saveButton.innerText = "Save";
  241. saveButton.style.marginRight = "10px";
  242. saveButton.style.padding = "8px 12px";
  243. saveButton.style.backgroundColor = "#9232E4";
  244. saveButton.style.color = "white";
  245. saveButton.style.border = "none";
  246. saveButton.style.borderRadius = "4px";
  247. saveButton.style.cursor = "pointer";
  248. saveButton.style.fontSize = "14px";
  249. saveButton.style.fontWeight = "bold";
  250. saveButton.style.transition = "background-color 0.2s";
  251. saveButton.onmouseover = () => (saveButton.style.backgroundColor = "#7A1CC4");
  252. saveButton.onmouseout = () => (saveButton.style.backgroundColor = "#9232E4");
  253. buttonsContainer.appendChild(saveButton);
  254.  
  255. // Cancel button
  256. const cancelButton = document.createElement("button");
  257. cancelButton.innerText = "Cancel";
  258. cancelButton.style.padding = "8px 12px";
  259. cancelButton.style.backgroundColor = "#aaa";
  260. cancelButton.style.color = "white";
  261. cancelButton.style.border = "none";
  262. cancelButton.style.borderRadius = "4px";
  263. cancelButton.style.cursor = "pointer";
  264. cancelButton.style.fontSize = "14px";
  265. cancelButton.style.fontWeight = "bold";
  266. cancelButton.style.transition = "background-color 0.2s";
  267. cancelButton.onmouseover = () => (cancelButton.style.backgroundColor = "#888");
  268. cancelButton.onmouseout = () => (cancelButton.style.backgroundColor = "#aaa");
  269. buttonsContainer.appendChild(cancelButton);
  270.  
  271. modalContent.appendChild(buttonsContainer);
  272. modal.appendChild(modalContent);
  273. document.body.appendChild(modal);
  274.  
  275. // Modal event listeners
  276. button.addEventListener("click", () => {
  277. console.log("Keyword button clicked; opening modal.");
  278. modal.style.display = "block";
  279. });
  280. cancelButton.addEventListener("click", () => {
  281. console.log("Cancel button clicked; closing modal.");
  282. modal.style.display = "none";
  283. });
  284. saveButton.addEventListener("click", () => {
  285. const newPostKeywords = postInput.value.split(",").map(s => s.trim()).filter(s => s);
  286. const newCommentKeywords = commentInput.value.split(",").map(s => s.trim()).filter(s => s);
  287. postKeywords = newPostKeywords;
  288. commentKeywords = newCommentKeywords;
  289. localStorage.setItem("redditPostKeywords", JSON.stringify(postKeywords));
  290. localStorage.setItem("redditCommentKeywords", JSON.stringify(commentKeywords));
  291. modal.style.display = "none";
  292. console.log("Save button clicked; keywords updated. Re-running filter.");
  293. // Remove all data-checked attributes so that hideContent() re-checks all content.
  294. document.querySelectorAll('[data-checked]').forEach(el => el.removeAttribute('data-checked'));
  295. hideContent();
  296. });
  297. }
  298.  
  299. // Initialize the UI.
  300. createKeywordUI();
  301.  
  302. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement