FA Content Filter

Filters user-defined content while browsing FA.

当前为 2015-12-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name FA Content Filter
  3. // @namespace fa-filter
  4. // @description Filters user-defined content while browsing FA.
  5. // @include *://www.furaffinity.net/*
  6. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
  7. // @version 1.3.0
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_deleteValue
  11. // @grant GM_openInTab
  12. // ==/UserScript==
  13.  
  14. // === WARNING ===
  15. // THE TAG FUNCTIONS ARE COMMENTED OUT IN ORDER TO PREVENT ACCIDENTAL DDoS DETECTION ON FURAFFINITY.
  16. this.$ = this.jQuery = jQuery.noConflict(true);
  17.  
  18. // === INITIALIZE USER ARRAY ===
  19. var userArray = JSON.parse(GM_getValue('userList', '{}'));
  20. //var tagArray = JSON.parse(GM_getvalue('tagList', '{}'));
  21.  
  22. // === FILTER ===
  23. var parseSettings = function() {
  24. if (!(userArray instanceof Array)) {
  25. $.each(userArray, function(username, data) {
  26. if (data['subs'] === 1) { hideSubmissions(username); }
  27. if (data['shouts'] === 1) { hideShouts(username); }
  28. if (data['coms'] === 1) { hideComments(username); }
  29. if (data['notifications'] === 1) { hideNotifications(username); }
  30. });
  31. }
  32. }
  33.  
  34. //var parseTagSettings = function() {
  35. // $('.t-image a[href^="/view"]').each(function() {
  36. // var url = $(this).attr('href');
  37. // console.log(url);
  38. // $.post(url, function(data) {
  39. // console.log($('#keywords', data).text());
  40. // });
  41. // });
  42. //}
  43.  
  44.  
  45. // === SAVE ===
  46. function writeSettings() {
  47. GM_setValue('userList', JSON.stringify(userArray));
  48. }
  49.  
  50. // === FUNCTIONS ===
  51. // Hide user submissions
  52. function hideSubmissions(username) {
  53. // Browse/Submissions
  54. var submission1 = $('.t-image a[href="/user/' + username + '/"]').closest('.t-image');
  55. stylizeHidden(submission1);
  56. // Mark Submissions as Checked
  57. submission1.children('small').children('input').prop('checked', true);
  58. submission1.addClass('hidden-sub').hide();
  59. // Favorites/Front Page
  60. var submission2 = $('b[id^="sid_"] img[src$="#' + username + '"]').closest('b');
  61. stylizeHidden(submission2);
  62. submission2.addClass('hidden-sub').hide();
  63. }
  64.  
  65. // Hide user shouts
  66. function hideShouts(username) {
  67. // Classic
  68. var shout = $('table[id^="shout-"] td.alt1 img[alt="' + username + '"]').closest('table[id^="shout-"]');
  69. shout.addClass('hidden-shout').hide();
  70. stylizeHidden(shout.find('table'));
  71. shout.next('br').addClass('hidden-shout-br').hide();
  72. // Beta
  73. var shoutBeta = $('table[id^="shout-"] .avatarcell img[alt="' + username +'"]').closest('table[id^="shout-"]');
  74. shoutBeta.addClass('hidden-shout').hide();
  75. stylizeHidden(shoutBeta.find('.usercommentbubble'));
  76. }
  77.  
  78. // Hide user comments and threads
  79. function hideComments(username) {
  80. // Classic
  81. var comments = $('.container-comment td.icon img[alt="' + username + '"]').closest('.container-comment');
  82. $(comments).each(function() {
  83. // Hide comment and get width
  84. if (!($(this).hasClass('hidden-comment'))) {
  85. var width = Number($(this).addClass('hidden-comment').hide().attr('width').slice(0,-1));
  86. var current = $(this).next('.container-comment');
  87.  
  88. // Iterate through comments until there's a width that is greater than or equal
  89. while (true) {
  90. if (current.length) {
  91. if (Number(current.attr('width').slice(0,-1)) < width) {
  92. current.addClass('hidden-comment').hide();
  93. current = current.next('.container-comment');
  94. } else {
  95. break;
  96. }
  97. } else {
  98. break;
  99. }
  100. }
  101. }
  102. });
  103. // Beta
  104. var commentsBeta = $('.usercommentseperator .avatarcell img[alt="' + username + '"]').closest('.usercommentseperator');
  105. stylizeHidden(commentsBeta.find('.usercommentbubble'));
  106. $(commentsBeta).each(function() {
  107. // Hide comment and get width
  108. if (!($(this).hasClass('hidden-comment'))) {
  109. var width = Number($(this).addClass('hidden-comment').hide().attr('width').slice(0,-1));
  110. var current = $(this).next('.usercommentseperator');
  111. // Iterate through the comments until there's a width that is greater than or equal
  112. while (true) {
  113. if (current.length) {
  114. if (Number(current.attr('width').slice(0,-1)) < width) {
  115. current.addClass('hidden-comment').hide();
  116. current = current.next('.usercommentseperator');
  117. } else {
  118. break;
  119. }
  120. } else {
  121. break;
  122. }
  123. }
  124. }
  125. });
  126. }
  127. // Hide user notifications
  128. function hideNotifications(username) {
  129. var notification = $('.message-stream a[href="/user/' + username + '/"]').closest('li');
  130. notification.addClass('hidden-notification').hide();
  131. stylizeHidden(notification);
  132. notification.children('input').prop('checked', true);
  133. // Classic only
  134. notification.children('table').children('tbody').children('tr').children('td').children('.checkbox').children('input').prop('checked', true);
  135. }
  136. function stylizeHidden(item) {
  137. item.css('background-color', '#FFBBBB');
  138. item.css('color', '#FF0000');
  139. $('a:link', item).css('color', '#FF0000');
  140. $('a:visited', item).css('color', '#FF0000');
  141. }
  142.  
  143. // === UI ===
  144. // == Filter Toggle ==
  145. // Submissions
  146. function filtersSubs() {
  147. if ($('.hidden-sub').length > 0) {
  148. $display = '<input style="float:right;" id="faf-toggle-subs" class="button" type="button" value="Toggle Filtered Submissions (' + $('.hidden-sub').length + ')"></input>';
  149. $('form').first().append($display);
  150. }
  151. }
  152.  
  153. // Followed Submissions
  154. function filtersSubsFollow() {
  155. if ($('.hidden-sub').length > 0) {
  156. $display = '<input id="faf-toggle-subs" class="button" type="button" value="Toggle Filtered Submissions (' + $('.hidden-sub').length + ')"></input>';
  157. $('.actions').append($display);
  158. }
  159. }
  160.  
  161. // Shouts
  162. function filtersShouts() {
  163. if ($('.hidden-shout').length > 0) {
  164. $display = '<center><input id="faf-toggle-shouts" class="button" type="button" value="Toggle Filtered Shouts (' + $('.hidden-shout').length + ')"></input></center>';
  165. // Classic
  166. $('table[id^="shout-"]').first().prevAll('table.maintable:first').append($display);
  167. // Beta
  168. $('.shoutboxcontainer').append($display);
  169. }
  170. }
  171.  
  172. // Shouts (Controls, Beta Only)
  173. function filtersShoutsControl() {
  174. if ($('.hidden-shout').length > 0) {
  175. $display = '<br><br><input id="faf-toggle-shouts" class="button" type="button" value = "Toggle Filtered Shouts (' + $('.hidden-shout').length + ')"></input>';
  176. $('div[id="controlpanel"] .alignright').append($display);
  177. $('.hidden-shout input').prop('checked', true);
  178. }
  179. }
  180.  
  181. // Comments
  182. function filtersComments() {
  183. if ($('.hidden-comment').length > 0) {
  184. $display = '<input style="float:right;" id="faf-toggle-comments" class="button" type="button" value="Toggle Filtered Comments (' + $('.hidden-comment').length + ')"></input>';
  185. // Classic
  186. $('table.container-comment').first().parent().parent().prev().children().append($display);
  187. // Beta
  188. $($display).insertAfter('.tags-row');
  189. }
  190. }
  191.  
  192. // Notifications
  193. function filtersNotifications() {
  194. if ($('.hidden-notification').length > 0) {
  195. $display = '<input id="faf-toggle-notifications" class="button" type="button" value="Toggle Filtered Notifications (' + $('.hidden-notification').length + ')"></input>';
  196. $('.global-controls').append($display);
  197. // = Notification Count =
  198. // Classic
  199. if ($('fieldset[id^="messages-watches"] .hidden-notification').length > 0)
  200. $('fieldset[id^="messages-watches"] h3').append(' (' + $('fieldset[id^="messages-watches"] .hidden-notification').length + ' filtered)');
  201. if ($('fieldset[id^="messages-comments-submission"] .hidden-notification').length > 0)
  202. $('fieldset[id^="messages-comments-submission"] h3').append(' (' + $('fieldset[id^="messages-comments-submission"] .hidden-notification').length + ' filtered)');
  203. if ($('fieldset[id^="messages-shouts"] .hidden-notification').length > 0)
  204. $('fieldset[id^="messages-shouts"] h3').append(' (' + $('fieldset[id^="messages-shouts"] .hidden-notification').length + ' filtered)');
  205. if ($('fieldset[id^="messages-favorites"] .hidden-notification').length > 0)
  206. $('fieldset[id^="messages-favorites"] h3').append(' (' + $('fieldset[id^="messages-favorites"] .hidden-notification').length + ' filtered)');
  207. // Beta
  208. if ($('fieldset[id^="messages-watches"] .hidden-notification').length > 0)
  209. $('fieldset[id^="messages-watches"] h2').append(' (' + $('fieldset[id^="messages-watches"] .hidden-notification').length + ' filtered)');
  210. if ($('fieldset[id^="messages-comments-submission"] .hidden-notification').length > 0)
  211. $('fieldset[id^="messages-comments-submission"] h2').append(' (' + $('fieldset[id^="messages-comments-submission"] .hidden-notification').length + ' filtered)');
  212. if ($('fieldset[id^="messages-shouts"] .hidden-notification').length > 0)
  213. $('fieldset[id^="messages-shouts"] h2').append(' (' + $('fieldset[id^="messages-shouts"] .hidden-notification').length + ' filtered)');
  214. if ($('fieldset[id^="messages-favorites"] .hidden-notification').length > 0)
  215. $('fieldset[id^="messages-favorites"] h2').append(' (' + $('fieldset[id^="messages-favorites"] .hidden-notification').length + ' filtered)');
  216. }
  217. }
  218.  
  219. // Show/Hide Submissions
  220. $(document.body).on('click', '#faf-toggle-subs', function() {
  221. $('.hidden-sub').toggle();
  222. });
  223.  
  224. // Show/Hide Shouts
  225. $(document.body).on('click', '#faf-toggle-shouts', function() {
  226. $('.hidden-shout').toggle();
  227. $('.hidden-shout-br').toggle();
  228. });
  229.  
  230. // Show/Hide Comments
  231. $(document.body).on('click', '#faf-toggle-comments', function() {
  232. $('.hidden-comment').toggle();
  233. })
  234.  
  235. // Show/Hide Notifications
  236. $(document.body).on('click', '#faf-toggle-notifications', function() {
  237. $('.hidden-notification').toggle();
  238. })
  239.  
  240. // == User Settings ==
  241. function displaySettings() {
  242. // Navbar link
  243. $('<li class="noblock"><a target="_blank" href="/controls/site-settings#fa-filter">FA Filter</a></li>').insertAfter($('li.sfw-toggle'));
  244. if (window.location.pathname.lastIndexOf('/controls/site-settings', 0) === 0) {
  245. // Brute forced, but there are no tables in the beta layout site-settings page. This is one of the major differences.
  246. if (!$('table').length) {
  247. // HTML Code
  248. var settingsDisplay = '<h2 id="fa-filter">FA Filter</h2>' +
  249. '<div class="cplineitem">' +
  250. '<div class="cprow">' +
  251. '<div class="cpcell">' +
  252. '<strong>Add a User</strong><br/>' +
  253. '<p>Tired of seeing somebody\'s contributions on the site? Add them to your filter list!<br/><strong>Note:</strong> Enter in the username of the person you want to filter, which is the username that would appear after "furaffinity.net/user/".' +
  254. '</div>' +
  255. '<div class="cpcell cptoggle">' +
  256. '<input class="textbox" type="text" id="faf-add-username" maxlength="50"></input><br\><br\><input id="faf-add" class="button" type="button" value="Add User" />' +
  257. '</div>' +
  258. '</div>' +
  259. '</div>' +
  260. '<table id="activity-periods-list" class="maintable" width="100%" cellspacing="1" cellpadding="0" border="0">' +
  261. '<tbody>' +
  262. '<tr>' +
  263. '<td class="alt1">' +
  264. '<table class="maintable container faf-list" width="100%" cellspacing="1" cellpadding="2" border="0">' +
  265. '<tr><td class="cat" align="left"><b>Username</b></td><td class="cat" width="200px"><b>Submissions</b></td><td class="cat" width="200px"><b>Shouts</b></td><td class="cat" width="200px"><b>Comments</b></td><td class="cat" width="200px"><b>Notifications</b></td></tr>' +
  266. '</table>' +
  267. '<br/><input class="button" id="faf-update" type="button" value="Update Filters"> <span class="faf-update-status" style="font-weight: bold; color: #006600; display: none;">Update successful!</span>' +
  268. '</td>' +
  269. '</tr>' +
  270. '</tbody>' +
  271. '</table>';
  272. $(settingsDisplay).insertAfter('.cplineitem:last');
  273. } else {
  274. // HTML Code
  275. var settingsDisplay = '<table id="fa-filter" cellpadding="0" cellspacing="1" border="0" class="section maintable"><tbody>' +
  276. '<tr><td height="22" class="cat links">&nbsp;<strong>FA Filter</strong></td></tr>' +
  277. '<tr><td class="alt1 addpad ucp-site-settings" align="center">' +
  278. '<table cellspacing="1" cellpadding="0" border="0"><tbody>' +
  279. '<tr>' +
  280. '<th><strong>Add a User</strong></th>' +
  281. '<td><input type="text" id="faf-add-username" maxlength="50"></input>&nbsp;<input id="faf-add" class="button" type="button" value="Add User"></td>' +
  282. '<td class="option-description">' +
  283. '<h3>Hide a user\'s contributions to the site.</h3>' +
  284. '<p>Tired of seeing somebody\'s contributions on the site? Add them to your filter list!<br>Note: Enter in the username of the person you want to filter, which is the username that would appear after "furaffinity.net/user/".</p>' +
  285. '</td>' +
  286. '</tr>' +
  287. '<tr>' +
  288. '<th class="noborder" style="vertical-align: text-top;"><strong style="position: relative; top: 25px;">Modify Filters</strong></th>' +
  289. '<td class="noborder">' +
  290. '<table cellspacing="0" cellpadding="0" border="0" class="faf-list">' +
  291. '<tr><th><strong>Username</strong></th><th><strong>Submissions</strong></th><th><strong>Shouts</strong></th><th><strong>Comments</strong></th><th><strong>Notifications</strong></th></tr>' +
  292. '</table>' +
  293. '<br><br><input class="button" id="faf-update" type="button" value="Update Filters"> <span class="faf-update-status" style="font-weight: bold; color: #006600; display: none;">Update successful!</span>' +
  294. '</td>' +
  295. '<td class="option-description noborder">' +
  296. '<h3>Choose what items you don\'t want to see.</h3>' +
  297. '<p>If you still want to see some of the things that a user contributes, you can control that here.</p>' +
  298. '</td>' +
  299. '</tr>' +
  300. '</tbody></table>' +
  301. '</td></tr>' +
  302. '</tbody></table>';
  303. $('form').append(settingsDisplay);
  304. }
  305. // Populate list
  306. $.each(userArray, function(username, data) {
  307. addFilterUser(username, data);
  308. });
  309. }
  310. }
  311.  
  312. // Display user in the filter table
  313. function addFilterUser(username, data) {
  314. var row = '<tr class="checked" id="filter-' + username + '"><td class="noborder"><a class="fa-filter-remove" id="faf-rm-' + username + '" href="#!">[x]</a> ' + username + '</td>';
  315. if (data['subs'] === 1) { row += '<td class="noborder"><input id="faf-check-subs-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-subs-' + username + '" type="checkbox"></td>'; }
  316. if (data['shouts'] === 1) { row += '<td class="noborder"><input id="faf-check-shouts-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-shouts-' + username + '" type="checkbox"></td>'; }
  317. if (data['coms'] === 1) { row += '<td class="noborder"><input id="faf-check-coms-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-coms-' + username + '" type="checkbox"></td>'; }
  318. if (data['notifications'] === 1) { row += '<td class="noborder"><input id="faf-check-notifications-' + username + '" type="checkbox" checked="checked"></td>'; } else { row += '<td class="noborder"><input id="faf-check-notifications-' + username + '" type="checkbox"></td>'; }
  319. row += '</tr>';
  320.  
  321. $('table.faf-list tr:last').after(row);
  322. }
  323.  
  324. // Add
  325. $(document.body).on('click', '#faf-add', function() {
  326. var username = $.trim($('#faf-add-username').val());
  327. $('#faf-add-username').val('');
  328. if (username !== '') {
  329. username = username.toLowerCase();
  330. if (!(username in userArray)) {
  331. userArray[username] = {'subs':1, 'shouts':1, 'coms':1, 'notifications':1};
  332. addFilterUser(username, userArray[username]);
  333. }
  334. }
  335. });
  336.  
  337. // Remove
  338. $(document.body).on('click', 'a.fa-filter-remove', function(event) {
  339. var username = event.target.id.substr(7);
  340. delete userArray[username];
  341. // Replace periods/colons with escaped versions. Who the fuck allows periods in usernames, seriously?
  342. userEsc = username.replace(/\./, '\\.');
  343. userEsc = userEsc.replace(/:/, '\:');
  344. console.log(userEsc)
  345. $('table.faf-list tr#filter-' + userEsc).remove();
  346. });
  347.  
  348. // Update
  349. $(document.body).on('click', '#faf-update', function() {
  350. $('.faf-list tr[id^="filter-"]').each(function() {
  351. var username = this.id.substr(7);
  352. var vals = {'subs':0, 'shouts':0, 'coms':0, 'notifications':0};
  353. // Replace periods/colons with escaped versions. Who the fuck allows periods in usernames, seriously?
  354. userEsc = username.replace(/\./, '\\.');
  355. userEsc = userEsc.replace(/:/, '\:');
  356. // Check checkboxes
  357. if ($('#faf-check-subs-' + userEsc).is(':checked')) { vals['subs'] = 1; }
  358. if ($('#faf-check-shouts-' + userEsc).is(':checked')) { vals['shouts'] = 1; }
  359. if ($('#faf-check-coms-' + userEsc).is(':checked')) { vals['coms'] = 1; }
  360. if ($('#faf-check-notifications-' + userEsc).is(':checked')) { vals['notifications'] = 1; }
  361. userArray[username] = vals;
  362. });
  363. // Save
  364. writeSettings();
  365. // Display message
  366. $('.faf-update-status').fadeIn('slow');
  367. setTimeout(function() {
  368. $('.faf-update-status').fadeOut('slow');
  369. }, 5000);
  370. });
  371.  
  372. displaySettings();
  373.  
  374. setTimeout(parseSettings, 50);
  375. //setTimeout(parseTagSettings, 100);
  376.  
  377. // Submissions
  378. if (window.location.pathname.lastIndexOf('/browse', 0) === 0) setTimeout(filtersSubs, 100);
  379. else if (window.location.pathname.lastIndexOf('/favorites', 0) === 0) setTimeout(filtersSubs, 100);
  380. else if (window.location.pathname.lastIndexOf('/msg/submissions', 0) === 0) setTimeout(filtersSubsFollow, 100);
  381. // Shouts
  382. else if (window.location.pathname.lastIndexOf('/user', 0) === 0) setTimeout(filtersShouts, 100);
  383. else if (window.location.pathname.lastIndexOf('/controls/shouts', 0) === 0) setTimeout(filtersShoutsControl, 100);
  384. // Comments
  385. else if (window.location.pathname.lastIndexOf('/view', 0) === 0) setTimeout(filtersComments, 100);
  386. // Notifications
  387. else if (window.location.pathname.lastIndexOf('/msg/others', 0) === 0) setTimeout(filtersNotifications, 100);