NGA Filter

troll must die

当前为 2019-12-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name NGA Filter
  3. // @namespace https://greasyfork.org/users/263018
  4. // @version 0.7.1
  5. // @author snyssss
  6. // @description troll must die
  7. // @match *bbs.nga.cn/thread.php?fid=*
  8. // @match *bbs.nga.cn/read.php?tid=*
  9. // @match *ngabbs.com/thread.php?fid=*
  10. // @match *ngabbs.com/read.php?tid=*
  11. // @grant GM_registerMenuCommand
  12. // @noframes
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. "use strict";
  17.  
  18. const dataKey = "troll_data";
  19. const modeKey = "troll_mode";
  20. const keywordKey = "troll_keyword";
  21.  
  22. let trollMap = (function() {
  23. try {
  24. return JSON.parse(localStorage.getItem(dataKey)) || {};
  25. } catch (e) {
  26. localStorage.setItem(dataKey, "{}");
  27. }
  28. return {};
  29. })();
  30.  
  31. let filterMode = ~~localStorage.getItem(modeKey);
  32.  
  33. let filterKeyword = localStorage.getItem(keywordKey) || "";
  34.  
  35. const isTroll = function(uid) {
  36. uid = ~~uid;
  37. if (uid) {
  38. return trollMap[uid];
  39. }
  40. return false;
  41. };
  42.  
  43. const isMatch = function(text) {
  44. if (!!filterKeyword && text.search(filterKeyword) >= 0) {
  45. return true;
  46. }
  47. return false;
  48. };
  49.  
  50. const toggleTroll = function(uid, tag) {
  51. uid = ~~uid;
  52. if (uid) {
  53. if (trollMap[uid] && tag === null) {
  54. delete trollMap[uid];
  55. } else {
  56. trollMap[uid] = tag ? [tag] : [];
  57. }
  58. localStorage.setItem(dataKey, JSON.stringify(trollMap));
  59. }
  60. };
  61.  
  62. const getUID = function(e) {
  63. let ele = e.getElementsByClassName("author")[0];
  64. if (ele) {
  65. return ele.search.match(/uid=(\S*)/)[1];
  66. }
  67. };
  68.  
  69. const getLink = function(e) {
  70. let ele = e.getElementsByClassName("topic")[0];
  71. ele.hide = function() {
  72. if (filterMode) {
  73. e.remove();
  74. } else {
  75. ele.style.textDecoration = "line-through";
  76. }
  77. };
  78. return ele;
  79. };
  80.  
  81. const getToggleButton = function(e) {
  82. let ele = e.getElementsByClassName("author")[0].nextElementSibling;
  83. if (ele.nextElementSibling) {
  84. ele = ele.nextElementSibling;
  85. }
  86. let uid = ~~ele.text;
  87. if (uid) {
  88. if (isTroll(uid)) {
  89. ele.style.background = "#CB4042";
  90. } else {
  91. ele.style.background = "#AAA";
  92. }
  93. return ele;
  94. } else {
  95. ele.onclick = null;
  96. }
  97. };
  98.  
  99. const getAvatar = function(e) {
  100. let ele = e.getElementsByClassName("avatar")[0] || {
  101. style: { display: "" }
  102. };
  103. ele.show =
  104. ele.show ||
  105. function() {
  106. ele.style.display = "";
  107. };
  108. ele.hide =
  109. ele.hide ||
  110. function() {
  111. ele.style.display = "none";
  112. };
  113. return ele;
  114. };
  115.  
  116. const getContent = function(e) {
  117. let uid = getUID(e);
  118. let name = "$troll_" + uid;
  119. let ele = e.getElementsByClassName("postcontent")[0] || { innerHTML: "" };
  120. ele.content = ele.content || ele.innerHTML;
  121. ele.show =
  122. ele.show ||
  123. function() {
  124. if (filterMode) {
  125. e.style.display = "";
  126. } else {
  127. ele.innerHTML = ele.content;
  128. }
  129. };
  130. ele.hide =
  131. ele.hide ||
  132. function() {
  133. if (filterMode) {
  134. e.style.display = "none";
  135. } else {
  136. ele.innerHTML =
  137. '<div class="lessernuke" style="background: #81C7D4; border-color: #66BAB7;">' +
  138. '<span class="crimson">Troll must die.</span> ' +
  139. '<a href="javascript:void(0)" onclick="var x = document.getElementsByName(&quot;' +
  140. name +
  141. '&quot;);for(var i=0;i<x.length;i++){x[i].style.display=&quot;&quot;}">点击查看</a>' +
  142. '<div style="display:none" name="' +
  143. name +
  144. '">' +
  145. ele.content +
  146. "</div>" +
  147. "</div>";
  148. }
  149. };
  150. return ele;
  151. };
  152.  
  153. const getTag = function(e) {
  154. let container = e.getElementsByClassName("posterinfo")[0];
  155. let ele = container.children[1];
  156. if (ele.tagName === "IMG") {
  157. ele = container.children[2];
  158. }
  159. if (ele.className !== "crimson") {
  160. let t = document.createElement("div");
  161. t.className = "crimson";
  162. t.style = "display: none;";
  163. if (ele.getAttribute("name") === "honor") {
  164. t.honor = ele;
  165. }
  166. ele.before(t);
  167. ele = t;
  168. }
  169. let uid = getUID(e);
  170. if (isTroll(uid)) {
  171. if (typeof trollMap[uid] === "object" && trollMap[uid].length) {
  172. ele.innerHTML = trollMap[uid][0];
  173. } else {
  174. ele.innerHTML = "";
  175. }
  176. }
  177. ele.show =
  178. ele.show ||
  179. function() {
  180. if (ele.innerHTML) {
  181. ele.style.display = "";
  182. }
  183. if (ele.honor) {
  184. ele.honor.style.display = "none";
  185. }
  186. };
  187. ele.hide =
  188. ele.hide ||
  189. function() {
  190. ele.style.display = "none";
  191. if (ele.honor) {
  192. ele.honor.style.display = "";
  193. }
  194. };
  195. return ele;
  196. };
  197.  
  198. const observerElements = [
  199. (function() {
  200. let container = document.getElementById("topicrows");
  201. let func = function(e) {
  202. if (e.tagName == "SCRIPT") return;
  203. let uid = getUID(e);
  204. let link = getLink(e);
  205. if (isTroll(uid) || isMatch(link.innerHTML)) {
  206. link.hide();
  207. }
  208. };
  209. return [container, func];
  210. })(),
  211. (function() {
  212. let container = document.getElementById("m_posts_c");
  213. let func = function(e) {
  214. if (e.tagName == "SCRIPT") return;
  215. let uid = getUID(e);
  216. let toggle = getToggleButton(e);
  217. if (toggle) {
  218. toggle.onclick = function(e) {
  219. let tag = null;
  220. if (e.ctrlKey) {
  221. tag = window.prompt("标签", (trollMap[uid] || {})[0]);
  222. if (tag === null) {
  223. return;
  224. }
  225. }
  226. toggleTroll(uid, tag);
  227. container.refilter();
  228. };
  229. } else {
  230. return;
  231. }
  232. let avatar = getAvatar(e);
  233. let content = getContent(e);
  234. let tag = getTag(e);
  235. if (isTroll(uid)) {
  236. avatar.hide();
  237. content.hide();
  238. tag.show();
  239. } else {
  240. avatar.show();
  241. content.show();
  242. tag.hide();
  243. }
  244. };
  245. return [container, func];
  246. })()
  247. ];
  248.  
  249. [].slice.call(observerElements).forEach(function(e) {
  250. if (!e[0]) return;
  251.  
  252. e[0].refilter = function() {
  253. [].slice.call(e[0].children).forEach(function(c) {
  254. e[1](c);
  255. });
  256. };
  257.  
  258. e[0].refilter();
  259.  
  260. let observer = new MutationObserver(function(mutations) {
  261. mutations.forEach(function(mutation) {
  262. if (mutation.addedNodes.length) {
  263. e[1](mutation.addedNodes[0]);
  264. }
  265. });
  266. });
  267.  
  268. observer.observe(e[0], {
  269. childList: true
  270. });
  271. });
  272.  
  273. if (filterMode) {
  274. GM_registerMenuCommand("过滤模式:删除", () => {
  275. localStorage.setItem(modeKey, 0);
  276. location.reload();
  277. });
  278. } else {
  279. GM_registerMenuCommand("过滤模式:标记", () => {
  280. localStorage.setItem(modeKey, 1);
  281. location.reload();
  282. });
  283. }
  284.  
  285. GM_registerMenuCommand("修改过滤关键词", () => {
  286. let result = window.prompt('过滤关键词,用"|"隔开', filterKeyword);
  287. if (result === null || result === filterKeyword) {
  288. return;
  289. }
  290. localStorage.setItem(keywordKey, result);
  291. location.reload();
  292. });
  293. })();