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.tagName === 'IMG') {
  144. ele = container.children[2];
  145. }
  146. if (ele.className !== 'crimson') {
  147. let t = document.createElement('div');
  148. t.className = 'crimson';
  149. t.style = 'display: none;';
  150. if (ele.getAttribute('name') === 'honor') {
  151. t.honor = ele;
  152. }
  153. ele.before(t);
  154. ele = t;
  155. }
  156. let uid = getUID(e);
  157. if (isTroll(uid)) {
  158. if (typeof (trollMap[uid]) === 'object' &&
  159. trollMap[uid].length) {
  160. ele.innerHTML = trollMap[uid][0];
  161. } else {
  162. ele.innerHTML = '';
  163. }
  164. }
  165. ele.show = ele.show || function () {
  166. if (ele.innerHTML) {
  167. ele.style.display = '';
  168. }
  169. if (ele.honor) {
  170. ele.honor.style.display = 'none';
  171. }
  172. }
  173. ele.hide = ele.hide || function () {
  174. ele.style.display = 'none';
  175. if (ele.honor) {
  176. ele.honor.style.display = '';
  177. }
  178. }
  179. return ele;
  180. };
  181.  
  182. const observerElements = [
  183. (function () {
  184. let container = document.getElementById('topicrows');
  185. let func = function (e) {
  186. if (e.tagName == 'SCRIPT') return;
  187. let uid = getUID(e);
  188. let link = getLink(e);
  189. if (isTroll(uid) ||
  190. isMatch(link.innerHTML)) {
  191. link.hide();
  192. }
  193. }
  194. return [
  195. container,
  196. func
  197. ]
  198. })(),
  199. (function () {
  200. let container = document.getElementById('m_posts_c');
  201. let func = function (e) {
  202. if (e.tagName == 'SCRIPT') return;
  203. let uid = getUID(e);
  204. let toggle = getToggleButton(e);
  205. if (toggle) {
  206. toggle.onclick = function (e) {
  207. let tag = null;
  208. if (e.ctrlKey) {
  209. tag = window.prompt('标签', (trollMap[uid] || {})[0]);
  210. if (tag === null) {
  211. return;
  212. }
  213. }
  214. toggleTroll(uid, tag);
  215. container.refilter();
  216. };
  217. } else {
  218. return;
  219. }
  220. let avatar = getAvatar(e);
  221. let content = getContent(e);
  222. let tag = getTag(e);
  223. if (isTroll(uid)) {
  224. avatar.hide();
  225. content.hide();
  226. tag.show();
  227. }
  228. else {
  229. avatar.show();
  230. content.show();
  231. tag.hide();
  232. }
  233. }
  234. return [
  235. container,
  236. func
  237. ]
  238. })()
  239. ];
  240.  
  241. [].slice.call(observerElements).forEach(function (e) {
  242. if (!e[0]) return;
  243.  
  244. e[0].refilter = function () {
  245. [].slice.call(e[0].children).forEach(function (c) {
  246. e[1](c);
  247. });
  248. }
  249.  
  250. e[0].refilter();
  251.  
  252. let observer = new MutationObserver(function (mutations) {
  253. mutations.forEach(function (mutation) {
  254. if (mutation.addedNodes.length) {
  255. e[1](mutation.addedNodes[0]);
  256. }
  257. });
  258. });
  259.  
  260. observer.observe(e[0], {
  261. childList: true
  262. });
  263. });
  264.  
  265. if (filterMode) {
  266. GM_registerMenuCommand('过滤模式:删除', () => {
  267. localStorage.setItem(modeKey, 0);
  268. location.reload();
  269. });
  270. } else {
  271. GM_registerMenuCommand('过滤模式:标记', () => {
  272. localStorage.setItem(modeKey, 1);
  273. location.reload();
  274. });
  275. }
  276.  
  277. GM_registerMenuCommand('修改过滤关键词', () => {
  278. let result = window.prompt('过滤关键词,用\"|\"隔开', filterKeyword);
  279. if (result === null ||
  280. result === filterKeyword) {
  281. return;
  282. }
  283. localStorage.setItem(keywordKey, result);
  284. location.reload();
  285. });
  286. })();