Reddit Robin Filter

Filters comments. Works on usernames and messages.

当前为 2016-04-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Reddit Robin Filter
  3. // @namespace http://kmcgurty.com
  4. // @version 2.3
  5. // @description Filters comments. Works on usernames and messages.
  6. // @author Kmc - admin@kmcdeals.com
  7. // @match https://www.reddit.com/robin
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_deleteValue
  11. // @grant GM_addStyle
  12. // ==/UserScript==
  13.  
  14. //GM_deleteValue("filter_list");
  15.  
  16. //will click the grow button and type /count every 15 seconds (to prevent abandoning)
  17. setInterval(function() {
  18. if($(".text-counter-input")[0].value == ""){
  19. $(".robin-chat--vote-increase").click();
  20. $(".text-counter-input")[0].value = "/count";
  21. $("input[type=submit]").click();
  22. }
  23. }, 15000);
  24.  
  25. //setup the default filter
  26. var defaultFilter = ["voted to grow", "voted to stay", "voted to abandon"];
  27. if (GM_getValue("filter_list") === undefined || typeof GM_getValue("filter_list") !== "object") GM_setValue("filter_list", defaultFilter);
  28.  
  29. //filtery things
  30. function doFilter(div) {
  31. var filter = GM_getValue("filter_list");
  32.  
  33. for (var i = 0; i < filter.length; i++) {
  34. var messageDiv = $(div).find(".robin-message--message");
  35. var usernameDiv = messageDiv.parent().find(".robin--username");
  36.  
  37. //messageDiv[0] is occasionally undefined?
  38. if (messageDiv[0] != undefined) {
  39. var message = messageDiv[0].innerHTML.toLowerCase();
  40. var currentFilter = filter[i].toLowerCase();
  41. var matches = message.includes(currentFilter);
  42.  
  43. var isAscii = $("#remove-ascii")[0].checked && isAsciiArt(message);
  44.  
  45. var silentDelete = $("#silent-delete")[0].checked;
  46.  
  47. if (matches || isAscii) {
  48. deleteMessage(messageDiv, silentDelete);
  49. }
  50. }
  51.  
  52. if(usernameDiv[0] != undefined){
  53. var username = usernameDiv[0].innerHTML.toLowerCase();
  54. var matches = username.includes(currentFilter);
  55.  
  56. var silentDelete = $("#silent-delete")[0].checked;
  57.  
  58. if (matches) {
  59. deleteMessage(messageDiv, silentDelete);
  60. }
  61. }
  62. }
  63. }
  64.  
  65. function parseURLs(messageDiv){
  66. var messageDiv = $(messageDiv).find(".robin-message--message")[0];
  67.  
  68. var text = messageDiv.innerHTML;
  69. var parsedText = text.replace(/(\r\n|\r|\n)/g, '<br/>').replace(/((?:(http|https|Http|Https|rtsp|Rtsp):\/\/(?:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,64}(?:\:(?:[a-zA-Z0-9\$\-\_\.\+\!\*\'\(\)\,\;\?\&\=]|(?:\%[a-fA-F0-9]{2})){1,25})?\@)?)?((?:(?:[a-zA-Z0-9][a-zA-Z0-9\-]{0,64}\.)+(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnrwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eouw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw]))|(?:(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\:\d{1,5})?)(\/(?:(?:[a-zA-Z0-9\;\/\?\:\@\&\=\#\~\-\.\+\!\*\'\(\)\,\_])|(?:\%[a-fA-F0-9]{2}))*)?(?:\b|$)/gi, "<a class='link' href='http://$3$4' target='_blank'>$3$4</a>");
  70.  
  71. messageDiv.innerHTML = parsedText;
  72. }
  73.  
  74. function deleteMessage(messageDiv, silent){
  75. if(silent){
  76. messageDiv.parent().remove();
  77. } else {
  78. messageDiv.replaceWith(`
  79. <span class='deleted'>
  80. <a href="#" data-deleted="` + messageDiv[0].innerHTML + `">&#x3c;deleted&#x3e;</a>
  81. </span>
  82. `);
  83. }
  84. }
  85.  
  86.  
  87. function removeMaxMessages(){
  88. var maxMessages = parseInt($("#max-messages")[0].value);
  89. var numberOfMessages = $("#robinChatMessageList").children().length;
  90.  
  91. if(numberOfMessages > maxMessages){
  92. var messages = $("#robinChatMessageList").children();
  93. for(var i = numberOfMessages; i > maxMessages; i--){
  94. if(messages[0] != undefined){
  95. messages[0].remove();
  96. }
  97. }
  98. }
  99. }
  100.  
  101.  
  102. //checks for a new message, and then calls doFilter();
  103. createObserver();
  104. function createObserver() {
  105. var target = $('#robinChatMessageList')[0];
  106.  
  107. var observer = new MutationObserver(function(mutations) {
  108. mutations.forEach(function(mutation) {
  109. var messageDiv = mutation.addedNodes[0];
  110. if(messageDiv != undefined){
  111. doFilter(messageDiv);
  112. parseURLs(messageDiv);
  113. }
  114.  
  115. removeMaxMessages();
  116. });
  117. });
  118.  
  119. // configuration of the observer:
  120. var config = { childList: true };
  121.  
  122. // pass in the target node, as well as the observer options
  123. observer.observe(target, config);
  124. }
  125.  
  126. //ty to fam
  127. //http://stackoverflow.com/questions/8746882/jquery-contains-selector-uppercase-and-lower-case-issue
  128. //makes :contains case-insensitive
  129. jQuery.expr[':'].Contains = function(a, i, m) { return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0; };
  130.  
  131. //also thanks to this guy
  132. //http://stackoverflow.com/questions/147824/how-to-find-whether-a-particular-string-has-unicode-characters-esp-double-byte
  133. function isAsciiArt(s) { // "art"
  134. return /[^\u0000-\u00ff]/.test(s);
  135. }
  136.  
  137. createEventListeners();
  138. function createEventListeners(){
  139. $(document.body).on("click", ".filter-img#filter-remove", function(event){
  140. var filterList = GM_getValue("filter_list");
  141. var word = event.currentTarget.getAttribute("data-word");
  142. var index = filterList.indexOf(word);
  143.  
  144. filterList.splice(index, 1);
  145. GM_setValue("filter_list", filterList);
  146.  
  147. event.currentTarget.parentElement.outerHTML = "";
  148. });
  149.  
  150. $(document.body).on("click", ".filter-img#filter-create", function(){
  151. var newWord = window.prompt("Enter a new filter to add");
  152. if(newWord != null){
  153. appendWordToList(newWord);
  154.  
  155. var newFilterList = GM_getValue("filter_list");
  156. newFilterList.push(newWord);
  157. GM_setValue("filter_list", newFilterList);
  158. }
  159. });
  160. $(document.body).on("click", ".deleted a", function(event){
  161. event.preventDefault();
  162. var element = event.toElement;
  163.  
  164. element.outerHTML = $(element).attr("data-deleted");
  165. });
  166. }
  167.  
  168. //everything below is html/css stuff
  169.  
  170. createHTML();
  171. function createHTML(){
  172. var html = `
  173. <div>
  174. <div>Create word or username filters below by clicking the green +. Message /u/kmcgurty1 for help.</div>
  175. <input id="remove-ascii" type="checkbox" checked>&nbsp;Remove ascii art<br>
  176. <input id="silent-delete" type="checkbox" checked>&nbsp;Silently delete<br>
  177. <input id="max-messages" type="number" value="150" style="width: 3em">&nbsp;Max messages to keep
  178. <div class="filter-list">
  179. <div class="item-wrapper">
  180. <div class="filter-img" id="filter-create"></div>
  181. </div>
  182. </div>
  183. </div>
  184. `;
  185.  
  186. $("div[role=main]").after(html);
  187.  
  188. var filterList = GM_getValue("filter_list");
  189.  
  190. for (var i = 0; i < filterList.length; i++) {
  191. appendWordToList(filterList[i]);
  192. }
  193.  
  194. createButton = ``;
  195. }
  196.  
  197. function appendWordToList(word){
  198. var html = `
  199. <div class="item-wrapper">
  200. <div class="filter-word">` + word + `</div>
  201. <div class="filter-img" id="filter-remove" data-word="` + word + `" ></div>
  202. </div>
  203. `;
  204.  
  205. $(html).insertBefore(".item-wrapper:last");
  206. }
  207.  
  208. var css = `
  209. .deleted a{
  210. color: rgba(0,0,0, .4);
  211. }
  212.  
  213. div input{
  214. display: inline-block;
  215. vertical-align: bottom;
  216. }
  217.  
  218. .filter-word{
  219. color: black;
  220. height: 25px;
  221. padding-right: 10px;
  222. }
  223.  
  224. .filter-img{
  225. cursor: pointer;
  226. width: 15px;
  227. height: 15px;
  228. background-size: contain;
  229. background-repeat: no-repeat;
  230. background-position: center;
  231. }
  232.  
  233. .filter-img#filter-create{
  234. height: 25px;
  235. width: 25px;
  236. background-image: url(https://i.imgur.com/nw1I62o.png);
  237. }
  238.  
  239. .filter-img#filter-remove{
  240. background-image: url(https://i.imgur.com/3bYSOxq.png);
  241. }
  242.  
  243. .item-wrapper{
  244. display: inline-block;
  245. background-color: rgb(235, 235, 235);
  246. border: 4px solid rgba(20, 20, 20, .7);
  247. border-radius: 5px;
  248. padding: 2px;
  249. margin: 4px;
  250. }
  251.  
  252. .item-wrapper div{
  253. vertical-align: middle;
  254. display: table-cell;
  255. }
  256.  
  257. .filter-list{
  258. font: normal small verdana,arial,helvetica,sans-serif;
  259. line-height: 1em;
  260. margin: 5px;
  261. }
  262.  
  263. input::-webkit-outer-spin-button,
  264. input::-webkit-inner-spin-button {
  265. /* display: none; <- Crashes Chrome on hover */
  266. -webkit-appearance: none;
  267. margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
  268. }
  269.  
  270. a.link{
  271. color: blue;
  272. }
  273.  
  274. a.link:link {
  275. color: #0000EE;
  276. }
  277.  
  278. a:hover{
  279. text-decoration: underline;
  280. }
  281. `;
  282.  
  283. GM_addStyle(css);