Reddit User/Subreddit/Domain Filter

Filter Reddit posts based on the user, subreddit, or domain name.

目前为 2017-09-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Reddit User/Subreddit/Domain Filter
  3. // @namespace RedditUserSubDomainFilter
  4. // @description Filter Reddit posts based on the user, subreddit, or domain name.
  5. // @version 1.0.2
  6. // @author jcunews
  7. // @include https://www.reddit.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. var filterUser = JSON.parse(localStorage.filterUser || "[]"),
  12. filterSub = JSON.parse(localStorage.filterSub || "[]"),
  13. filterDomain = JSON.parse(localStorage.filterDomain || "[]"),
  14. posts, user, sub, domain, buttonTemplate, button, match, filtered;
  15.  
  16. function doFilter(dontHide) {
  17. posts = Array.prototype.slice.call(document.querySelectorAll(".thing"));
  18. posts.forEach(function(post,i) {
  19. user = post.querySelector(".author");
  20. if (user) {
  21. match = filterUser.indexOf(user.textContent) >= 0;
  22. filtered = match;
  23. button = user.nextSibling;
  24. if (!button || !button.getAttribute || !button.getAttribute("type")) {
  25. button = buttonTemplate.cloneNode(true);
  26. button.title = "Filter posts from this user (CTRL+Click to undo)";
  27. button.style.marginLeft = "";
  28. button.setAttribute("type", "user");
  29. button.setAttribute("value", user.textContent);
  30. button.onclick = setFilter;
  31. user.parentNode.insertBefore(button, user.nextSibling);
  32. }
  33. button.style.background = match ? "#b0b" : "#c00";
  34. } else filtered = false;
  35. sub = post.querySelector(".subreddit");
  36. if (sub) {
  37. match = filterSub.indexOf(sub.textContent.match(/\/?(.*)/)[1]) >= 0;
  38. if (!filtered) filtered = match;
  39. button = sub.nextSibling;
  40. if (!button || !button.getAttribute || !button.getAttribute("type")) {
  41. button = buttonTemplate.cloneNode(true);
  42. button.title = "Filter posts from this subreddit (CTRL+Click to undo)";
  43. button.setAttribute("type", "sub");
  44. button.setAttribute("value", sub.textContent.match(/\/?(.*)/)[1]);
  45. button.onclick = setFilter;
  46. sub.parentNode.insertBefore(button, sub.nextSibling);
  47. }
  48. button.style.background = match ? "#b0b" : "#c00";
  49. }
  50. domain = post.querySelector(".domain");
  51. if (domain) {
  52. match = filterDomain.indexOf(domain.textContent.match(/\((.*)\)/)[1]) >= 0;
  53. if (!filtered) filtered = match;
  54. button = domain.nextSibling;
  55. if (!button || !button.getAttribute || !button.getAttribute("type")) {
  56. button = buttonTemplate.cloneNode(true);
  57. button.title = "Filter posts from this domain (CTRL+Click to undo)";
  58. button.setAttribute("type", "domain");
  59. button.setAttribute("value", domain.textContent.match(/\((.*)\)/)[1]);
  60. button.onclick = setFilter;
  61. domain.parentNode.insertBefore(button, domain.nextSibling);
  62. }
  63. button.style.background = match ? "#b0b" : "#c00";
  64. }
  65. if (filtered) {
  66. if (!dontHide) {
  67. post.setAttribute("filtered", "1");
  68. post.style.display = "none";
  69. }
  70. } else {
  71. post.removeAttribute("filtered");
  72. post.style.display = "";
  73. }
  74. });
  75. }
  76.  
  77. function setFilter(ev) {
  78. var value, i;
  79. button = ev.target;
  80. value = button.getAttribute("value");
  81. if (!ev.ctrlKey) {
  82. //add filter
  83. switch (button.getAttribute("type")) {
  84. case "user":
  85. if (filterUser.indexOf(value) < 0) {
  86. filterUser.push(value);
  87. localStorage.filterUser = JSON.stringify(filterUser);
  88. }
  89. break;
  90. case "sub":
  91. if (filterSub.indexOf(value) < 0) {
  92. filterSub.push(value);
  93. localStorage.filterSub = JSON.stringify(filterSub);
  94. }
  95. break;
  96. default: //domain
  97. if (filterDomain.indexOf(value) < 0) {
  98. filterDomain.push(value);
  99. localStorage.filterDomain = JSON.stringify(filterDomain);
  100. }
  101. }
  102. } else {
  103. //remove filter
  104. switch (button.getAttribute("type")) {
  105. case "user":
  106. i = filterUser.indexOf(value);
  107. if (i >= 0) {
  108. filterUser.splice(i, 1);
  109. localStorage.filterUser = JSON.stringify(filterUser);
  110. }
  111. break;
  112. case "sub":
  113. i = filterSub.indexOf(value);
  114. if (i >= 0) {
  115. filterSub.splice(i, 1);
  116. localStorage.filterSub = JSON.stringify(filterSub);
  117. }
  118. break;
  119. default: //domain
  120. i = filterDomain.indexOf(value);
  121. if (i >= 0) {
  122. filterDomain.splice(i, 1);
  123. localStorage.filterDomain = JSON.stringify(filterDomain);
  124. }
  125. }
  126. }
  127. doFilter(ev.ctrlKey);
  128. }
  129.  
  130. function showFiltered() {
  131. posts = Array.prototype.slice.call(document.querySelectorAll(".thing[filtered]"));
  132. posts.forEach(function(post) {
  133. post.style.display = "";
  134. });
  135. }
  136.  
  137. if (!document.querySelector(".siteTable")) {
  138. //create button template
  139. buttonTemplate = document.createElement("DIV");
  140. buttonTemplate.textContent = "X";
  141. buttonTemplate.style.cssText = "\
  142. display:inline-block; margin-left:1ex; border-radius:4px; padding:0 .7ex; \
  143. background:#c00; text-align:center; line-height:normal; font-size: x-small; \
  144. font-weight:bold; color:#fff; cursor:pointer";
  145. //filter posts
  146. doFilter();
  147. //add link to show all filtered posts
  148. button = document.createElement("A");
  149. button.textContent = "Show Filtered";
  150. button.title = "Temporarily show filtered posts";
  151. button.style.marginLeft = "2ex";
  152. button.href = "javascript:void(0)";
  153. button.onclick = showFiltered;
  154. document.querySelector(".tabmenu").appendChild(button);
  155. //monitor dynamic post list
  156. if (window.siteTable_organic) {
  157. (new MutationObserver(function(records) {
  158. var newNodes = 0;
  159. records.forEach(function(record) {
  160. if (record.addedNodes) newNodes += record.addedNodes.length;
  161. });
  162. if (newNodes) doFilter();
  163. })).observe(window.siteTable_organic, { childList: true });
  164. }
  165. }