NGA Filter

troll must die

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

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