Robin Enhancement Script

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

Від 03.04.2016. Дивіться остання версія.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Robin Enhancement Script
// @namespace    https://www.reddit.com/
// @version      1.8
// @description  Highlight mentions, make link clickable, use channels & automatically remove spam
// @author       mr_bag
// @match        https://www.reddit.com/robin*
// @grant        none
// ==/UserScript==
(function() {

	// Grab users username + play nice with RES
	var robin_user = $("#header-bottom-right .user a").first().text();
	var ignored_users = {};

	/**
	 * Check if a message is "spam"
	 */
	var is_spam = function(line){
		return (
			// Hide auto vote messages
			(/^voted to (grow|stay|abandon)/.test(line)) ||
			// random unicode?
			(/[\u0080-\uFFFF]/.test(line)) ||
			// hide any auto voter messages
			(/\[.*autovoter.*\]/.test(line)) ||
			// Common bots
			(/^(\[binbot\]|\[robin-grow\])/.test(line)) ||
			// repeating chars in line (more than 5). e.g. aaaaaaa !!!!!!!!
			(/(.)\1{5,}/.test(line)) ||
			// Some common messages
			(/(voting will end in approximately|\[i spam the most used phrase\]|\[message from creator\])/.test(line)) ||
			// no spaces = spam if its longer than 25 chars (dont filter links)
			(line.indexOf(" ") === -1 && line.length > 25 && line.indexOf("http") === -1) ||
			// repeating same word
			/(\b\S+\b)\s+\b\1\b/i.test(line)
		);
	};

	/**
	 * Check if a message is from an ignored user
	 *
	 */
	var is_ignored = function($usr, $ele){
		// no user name, go looking for when said it
		if($usr.length === 0){
			while($usr.length === 0){
				$ele = $ele.prev();
				$usr = $ele.find(".robin--username");
			}
		}
		// are they ignored?
		return (ignored_users[$usr.text()]);
	};

	/**
	 * Make links clickable
	 *
	 */
	var auto_link = function($msg){
		var text = $msg.html(); // read as html so stuff stays escaped
		// normal links
		text = text.replace(/\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim, '<a target="blank" href="$&">$&</a>');
		// reddit subreddit links
		text = text.replace(/ \/r\/(\w+)/gim, ' <a target="blank" href="https://reddit.com/r/$1">/r/$1</a>');
		// update text
		$msg.html(text);
	};

	/**
	 * Mute a user
	 */
	var _mute_user = function(usr){
		// Add to ignore list
		ignored_users[usr] = true;
		_render_muted_list();
	};

	/**
	 * un-mute a user
	 */
	var _unmute_user = function(usr){
		// Add to ignore list
		delete ignored_users[usr];
		_render_muted_list();
	};

	// Render list of ignored users
	var _render_muted_list = function(){
		var html = "<strong>Ignored users</strong><br>";
		for(var u in ignored_users){
			html += "<div data-usr='"+ u + "'>" + u + " - [unmute]</div>";
		}
		$("#muted_users").html(html);
	};

	// Scroll chat back to bottom
	var _scroll_to_bottom = function(){
		$("#robinChatWindow").scrollTop($("#robinChatMessageList").height());
	};

	/**
	 * Parse a link and apply changes
	 */
	var parse_line = function($ele){
		var $msg = $ele.find(".robin-message--message");
		var $usr = $ele.find(".robin--username");

		var line = $msg.text().toLowerCase();

		// If user is ignored or message looks like "Spam". hide it
		if (is_ignored($usr, $ele) || is_spam(line)) {
			$ele.addClass("spam-hidden");
		}

		// Highlight mentions
		if(line.indexOf(robin_user) !== -1){
			$ele.css("font-weight", "bold");
		}

		// Make links clickable
		if(line.indexOf("http") !== -1){
			auto_link($msg);
		}

		// Add mute button to users
		if(!$ele.hasClass("robin--user-class--system") && $usr.text() != robin_user){
			$("<span style='font-size:.8em;cursor:pointer'> [mute] </span>").insertBefore($usr).click(function(){
				_mute_user($usr.text());
			});
		}

		// Add filter support
		if(line.indexOf("%") === 0){ $ele.addClass("filter-percent");}
		if(line.indexOf("$") === 0){ $ele.addClass("filter-dollar");}
		if(line.indexOf("#") === 0){ $ele.addClass("filter-hash"); }
		if(line.indexOf("~") === 0){ $ele.addClass("filter-tilde"); }
		if(line.indexOf("^") === 0){ $ele.addClass("filter-hat"); }
	};

	// Detect changes, are parse the new message
	$("#robinChatWindow").on('DOMNodeInserted', function(e) {
		if ($(e.target).is('div.robin-message')) {
			// Apply changes to line
			parse_line($(e.target));
		}
	});

	// When everything is ready
	$(document).ready(function(){
		// Set default spam filter type
		$("#robinChatWindow").addClass("hide-spam");

		// Add checkbox to toggle "hide" behaviors
		$("#robinDesktopNotifier").append("<label><input type='checkbox' checked='checked'>Hide spam completely</label>").click(function(){
			if($(this).find("input").is(':checked')){
				$("#robinChatWindow").removeClass("mute-spam").addClass("hide-spam");
			}else{
				$("#robinChatWindow").removeClass("hide-spam").addClass("mute-spam");
			}
			// correct scroll after spam filter change
			_scroll_to_bottom();
		});

		// Add Muted list & hook up unmute logic
		$('<div id="muted_users" class="robin-chat--sidebar-widget robin-chat--notification-widget"><strong>Ignored users</strong></div>').insertAfter($("#robinDesktopNotifier"));
		$('#muted_users').click(function(e){
			var user = $(e.target).data("usr");
			if(user) _unmute_user(user);
		});

		// Hook up toggles for filters
		$('<div id="filter_mode">Filter: <span data-filter="*">Show all</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="hide">No channels</span></div>').insertAfter("#robinSendMessage").click(function(e){
			var filter = $(e.target).data("filter");
			if(filter === '*'){
				$("#robinChatWindow").removeClass("filter_on").removeAttr("data-filter").removeClass("filter_all_channels");
			}else if(filter === 'hide'){
				$("#robinChatWindow").removeClass("filter_on").removeAttr("data-filter").addClass("filter_all_channels");
			}else{
				$("#robinChatWindow").addClass("filter_on").attr("data-filter", filter);
			}
			// correct scroll after filter change
			_scroll_to_bottom();
		});
		// Auto append % when in filtered mode
		$("#robinSendMessage").submit(function(){
			if($("#robinChatWindow").hasClass("filter_on")){
				if($(".text-counter-input").val().indexOf("/") !== 0){ // /commands should work as normal
					$(".text-counter-input").val($("#robinChatWindow").attr("data-filter") + " " + $(".text-counter-input").val());
				}
			}
		});
	});


	// filter styles
	document.styleSheets[0].insertRule("#robinChatWindow.filter_on div.robin-message { display:none; }", 0);
	document.styleSheets[0].insertRule("#robinChatWindow.filter_on[data-filter='$'] div.robin-message.filter-dollar,#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 div.robin-message.robin--user-class--system  { display:block; }", 0);
	document.styleSheets[0].insertRule("#robinChatWindow.filter_all_channels div.robin-message.filter-dollar,#robinChatWindow.filter_all_channels  div.robin-message.filter-hash, #robinChatWindow.filter_all_channels div.robin-message.filter-percent { display:none; }", 0);

	document.styleSheets[0].insertRule("#filter_mode span { cursor: pointer;}", 0);

	// Add initial styles for "spam" messages
	document.styleSheets[0].insertRule("#robinChat #robinChatWindow.hide-spam div.robin-message.spam-hidden { display:none; }", 0);
	document.styleSheets[0].insertRule("#robinChat #robinChatWindow.mute-spam div.robin-message.spam-hidden { opacity:0.3; font-size:1.2em; }", 0);

	// muted user box
	document.styleSheets[0].insertRule("#muted_users { font-size:1.2em; }", 0);
	document.styleSheets[0].insertRule("#muted_users div { padding: 2px 0; }", 0);
	document.styleSheets[0].insertRule("#muted_users strong { font-weight:bold; }", 0);

	// FIX RES nightmode (ish)
	document.styleSheets[0].insertRule(".res-nightmode #robinChatWindow div.robin-message { color: #ccc; }", 0);
})();