Robin Enhancement Script

Highlight mentions, make link clickable, use channels & automatically remove spam

目前为 2016-04-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Robin Enhancement Script
  3. // @namespace https://www.reddit.com/
  4. // @version 1.9.1
  5. // @description Highlight mentions, make link clickable, use channels & automatically remove spam
  6. // @author mr_bag
  7. // @match https://www.reddit.com/robin*
  8. // @grant none
  9. // ==/UserScript==
  10. (function() {
  11.  
  12. // Grab users username + play nice with RES
  13. var robin_user = $("#header-bottom-right .user a").first().text();
  14. var ignored_users = {};
  15.  
  16. // for spam counter - very important i know :P
  17. var blocked_spam_el = null;
  18. var blocked_spam = 0;
  19.  
  20. /**
  21. * Check if a message is "spam"
  22. */
  23. var is_spam = function(line){
  24. return (
  25. // Hide auto vote messages
  26. (/^voted to (grow|stay|abandon)/.test(line)) ||
  27. // random unicode?
  28. (/[\u0080-\uFFFF]/.test(line)) ||
  29. // hide any auto voter messages
  30. (/\[.*autovoter.*\]/.test(line)) ||
  31. // Common bots
  32. (/^(\[binbot\]|\[robin-grow\])/.test(line)) ||
  33. // repeating chars in line (more than 5). e.g. aaaaaaa !!!!!!!!
  34. (/(.)\1{5,}/.test(line)) ||
  35. // Some common messages
  36. (/(voting will end in approximately|\[i spam the most used phrase\]|\[message from creator\]|\[.*bot.*\])/.test(line)) ||
  37. // no spaces = spam if its longer than 25 chars (dont filter links)
  38. (line.indexOf(" ") === -1 && line.length > 25 && line.indexOf("http") === -1) ||
  39. // repeating same word
  40. /(\b\S+\b)\s+\b\1\b/i.test(line)
  41. );
  42. };
  43.  
  44. /**
  45. * Check if a message is from an ignored user
  46. *
  47. */
  48. var is_ignored = function($usr, $ele){
  49. // no user name, go looking for when said it
  50. if($usr.length === 0){
  51. while($usr.length === 0){
  52. $ele = $ele.prev();
  53. $usr = $ele.find(".robin--username");
  54. }
  55. }
  56. // are they ignored?
  57. return (ignored_users[$usr.text()]);
  58. };
  59.  
  60. /**
  61. * Make links clickable
  62. *
  63. */
  64. var auto_link = function($msg){
  65. var text = $msg.html(); // read as html so stuff stays escaped
  66. // normal links
  67. text = text.replace(/\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim, '<a target="blank" href="$&">$&</a>');
  68. // reddit subreddit links
  69. text = text.replace(/ \/r\/(\w+)/gim, ' <a target="blank" href="https://reddit.com/r/$1">/r/$1</a>');
  70. // update text
  71. $msg.html(text);
  72. };
  73.  
  74. /**
  75. * Mute a user
  76. */
  77. var _mute_user = function(usr){
  78. // Add to ignore list
  79. ignored_users[usr] = true;
  80. _render_muted_list();
  81. };
  82.  
  83. /**
  84. * un-mute a user
  85. */
  86. var _unmute_user = function(usr){
  87. // Add to ignore list
  88. delete ignored_users[usr];
  89. _render_muted_list();
  90. };
  91.  
  92. // Render list of ignored users
  93. var _render_muted_list = function(){
  94. var html = "<strong>Ignored users</strong><br>";
  95. for(var u in ignored_users){
  96. html += "<div data-usr='"+ u + "'>" + u + " - [unmute]</div>";
  97. }
  98. $("#muted_users").html(html);
  99. };
  100.  
  101. // Scroll chat back to bottom
  102. var _scroll_to_bottom = function(){
  103. $("#robinChatWindow").scrollTop($("#robinChatMessageList").height());
  104. };
  105.  
  106. var update_spam_count = function(){
  107. blocked_spam++;
  108. blocked_spam_el.innerHTML = blocked_spam;
  109. }
  110.  
  111. /**
  112. * Parse a link and apply changes
  113. */
  114. var parse_line = function($ele){
  115. var $msg = $ele.find(".robin-message--message");
  116. var $usr = $ele.find(".robin--username");
  117.  
  118. var line = $msg.text().toLowerCase();
  119.  
  120. // If user is ignored or message looks like "Spam". hide it
  121. if (is_ignored($usr, $ele) || is_spam(line)) {
  122. $ele.addClass("spam-hidden");
  123. update_spam_count();
  124. }
  125.  
  126. // Highlight mentions
  127. if(line.indexOf(robin_user) !== -1){
  128. $ele.css("font-weight", "bold");
  129. }
  130.  
  131. // Make links clickable
  132. if(line.indexOf("http") !== -1){
  133. auto_link($msg);
  134. }
  135.  
  136. // Add mute button to users
  137. if(!$ele.hasClass("robin--user-class--system") && $usr.text() != robin_user){
  138. $("<span style='font-size:.8em;cursor:pointer'> [mute] </span>").insertBefore($usr).click(function(){
  139. _mute_user($usr.text());
  140. });
  141. }
  142.  
  143. // Add filter support
  144. if(line.indexOf("%") === 0){ $ele.addClass("filter-percent in-channel");}
  145. if(line.indexOf("$") === 0){ $ele.addClass("filter-dollar in-channel");}
  146. if(line.indexOf("#") === 0){ $ele.addClass("filter-hash in-channel"); }
  147. if(line.indexOf("~") === 0){ $ele.addClass("filter-tilde in-channel"); }
  148. if(line.indexOf("^") === 0){ $ele.addClass("filter-hat in-channel"); }
  149. if(line.indexOf("+") === 0){ $ele.addClass("filter-plus in-channel"); }
  150. if(line.indexOf("&") === 0){ $ele.addClass("filter-and in-channel"); }
  151. if(line.indexOf("*") === 0){ $ele.addClass("filter-star in-channel"); }
  152. };
  153.  
  154. // Detect changes, are parse the new message
  155. $("#robinChatWindow").on('DOMNodeInserted', function(e) {
  156. if ($(e.target).is('div.robin-message')) {
  157. // Apply changes to line
  158. parse_line($(e.target));
  159. }
  160. });
  161.  
  162. // When everything is ready
  163. $(document).ready(function(){
  164. // Set default spam filter type
  165. $("#robinChatWindow").addClass("hide-spam");
  166.  
  167. // Add checkbox to toggle "hide" behaviors
  168. $("#robinDesktopNotifier").append("<label><input type='checkbox' checked='checked'>Hide spam completely (<span id='spamcount'>0</span> removed)</label>").click(function(){
  169. if($(this).find("input").is(':checked')){
  170. $("#robinChatWindow").removeClass("mute-spam").addClass("hide-spam");
  171. }else{
  172. $("#robinChatWindow").removeClass("hide-spam").addClass("mute-spam");
  173. }
  174. // correct scroll after spam filter change
  175. _scroll_to_bottom();
  176. });
  177.  
  178. blocked_spam_el = $("#spamcount")[0];
  179.  
  180. // Add Muted list & hook up unmute logic
  181. $('<div id="muted_users" class="robin-chat--sidebar-widget robin-chat--notification-widget"><strong>Ignored users</strong></div>').insertAfter($("#robinDesktopNotifier"));
  182. $('#muted_users').click(function(e){
  183. var user = $(e.target).data("usr");
  184. if(user) _unmute_user(user);
  185. });
  186.  
  187. // Hook up toggles for filters
  188. $('<div id="filter_mode">Filter: <span data-filter="none" style="font-weight:bold;">Everything</span> | <span data-filter="%">% Only</span> | <span data-filter="$">$ Only</span> | <span data-filter="#"># Only</span> | <span data-filter="~">~ Only</span> | <span data-filter="^">^ Only</span> | <span data-filter="&">&amp; Only</span> | <span data-filter="+">+ Only</span> | <span data-filter="*">* Only</span> | <span data-filter="channels">All channels</span> | <span data-filter="hide">Without channels</span></div>').insertAfter("#robinSendMessage").click(function(e){
  189. var filter = $(e.target).data("filter");
  190. // filter was toggled?
  191. if(!filter) return;
  192.  
  193. var robin_window = $("#robinChatWindow");
  194. // Toggle selected "tab"
  195. $(e.target).parent().find("span").css("font-weight", "normal");
  196. $(e.target).css("font-weight", "bold");
  197.  
  198. // remove filters
  199. robin_window.removeAttr("data-filter").removeClass("filter_on").removeClass("filter_all_channels").removeClass("filter_only_channels");
  200.  
  201. if(filter === 'none'){
  202. // Show all
  203. }else if(filter === 'hide'){
  204. // Hide any channel conversations
  205. robin_window.addClass("filter_all_channels");
  206. }else if(filter === 'channels'){
  207. // Hide any channel conversations
  208. robin_window.addClass("filter_only_channels");
  209. }else{
  210. // apply a filter
  211. robin_window.addClass("filter_on").attr("data-filter", filter);
  212. }
  213. // correct scroll after filter change
  214. _scroll_to_bottom();
  215. });
  216. // Auto append % when in filtered mode
  217. $("#robinSendMessage").submit(function(){
  218. if($("#robinChatWindow").hasClass("filter_on")){
  219. if($(".text-counter-input").val().indexOf("/") !== 0){ // /commands should work as normal
  220. $(".text-counter-input").val($("#robinChatWindow").attr("data-filter") + " " + $(".text-counter-input").val());
  221. }
  222. }
  223. });
  224. });
  225.  
  226. // filter for channel
  227. document.styleSheets[0].insertRule("#robinChatWindow.filter_on div.robin-message { display:none; }", 0);
  228. document.styleSheets[0].insertRule("#robinChatWindow.filter_on[data-filter='$'] div.robin-message.filter-dollar,#robinChatWindow.filter_on[data-filter='*'] div.robin-message.filter-star,#robinChatWindow.filter_on[data-filter='&'] div.robin-message.filter-and, #robinChatWindow.filter_on[data-filter='%'] div.robin-message.filter-percent,#robinChatWindow.filter_on[data-filter='#'] div.robin-message.filter-hash,#robinChatWindow.filter_on[data-filter='~'] div.robin-message.filter-tilde,#robinChatWindow.filter_on[data-filter='^'] div.robin-message.filter-hat,#robinChatWindow.filter_on[data-filter='+'] div.robin-message.filter-plus,#robinChatWindow.filter_on div.robin-message.robin--user-class--system { display:block; }", 0);
  229. // filter, hide all channels
  230. document.styleSheets[0].insertRule("#robinChatWindow.filter_all_channels div.robin-message.in-channel{ display:none; }", 0);
  231. // filter show all channels
  232. document.styleSheets[0].insertRule("#robinChatWindow.filter_only_channels div.robin-message {display:none; }", 0);
  233. document.styleSheets[0].insertRule("#robinChatWindow.filter_only_channels div.robin-message.in-channel { display:block; }", 0);
  234.  
  235. document.styleSheets[0].insertRule("#filter_mode span { cursor: pointer;}", 0);
  236.  
  237. // Add initial styles for "spam" messages
  238. document.styleSheets[0].insertRule("#robinChat #robinChatWindow.hide-spam div.robin-message.spam-hidden { display:none; }", 0);
  239. document.styleSheets[0].insertRule("#robinChat #robinChatWindow.mute-spam div.robin-message.spam-hidden { opacity:0.3; font-size:1.2em; }", 0);
  240.  
  241. // muted user box
  242. document.styleSheets[0].insertRule("#muted_users { font-size:1.2em; }", 0);
  243. document.styleSheets[0].insertRule("#muted_users div { padding: 2px 0; }", 0);
  244. document.styleSheets[0].insertRule("#muted_users strong { font-weight:bold; }", 0);
  245.  
  246. // FIX RES nightmode (ish)
  247. document.styleSheets[0].insertRule(".res-nightmode #robinChatWindow div.robin-message { color: #ccc; }", 0);
  248. })();