So if there are any of you interested in reading the chat on the TwitchPlaysPokemon stream without going insane, here's a little project I've worked on this week:
// ==UserScript==
// @name TPP Chat Filter
// @description Filter for Twitch Plays Pokemon to remove inputs from the chat
// @include http://www.twitch.tv/twitchplayspokemon
// @version 2.0
// @copyright 2014+, Roy Gallant
// @grant none
// ==/UserScript==
/*globals jQuery, CurrentChat, setInterval, window*/
/*jslint regexp: true*/
/****************************************/
/* Edit user settings below */
/****************************************/
var userSettings = {
interval: 500, // How often script runs (milliseconds)
hideBots: true, // Hides chat from blacklisted users
hideInputs: true, // Hides up/start/a/anarchy/etc commands.
hideSpam: true, // Removes duplicates of text.
libraryMode: true // Converts excessive caps to lowercase.
};
/****************************************/
/* Edit user settings above */
/****************************************/
(function ($, settings) {
'use strict';
var inputRegex, dupeRegex, upperRegex, changeMessages, botList, botHashSet;
inputRegex = /^((up|down|left|right|a|b|start|select)\d?)+|anarchy|democracy|wait$/i;
dupeRegex = /(.{4,}?)\1+/g;
upperRegex = /[A-Z][A-Z\s',]{5,}[A-Z]|[A-Z]{4,}/g;
changeMessages = settings.hideSpam || settings.libraryMode;
botHashSet = {};
if (settings.hideBots) {
botList = [
"2inchchode", "anarchynow13", "anaxasaurus", "arakdur", "arronax123456",
"badboxartmegaman", "balistico_league", "bdtzau", "beetwick",
"brokenfoxshard", "casperw123", "catzumiiii", "chunsern", "conanptt",
"crac_barber", "daydreamalicorn", "dewdewgong", "diresickfish",
"dj_bless71", "dweeksey", "eftj2", "emp_m2k", "epileppicpanda", "eroubis",
"erquint", "fattoler", "fc_infinite", "feedingwolves", "fephisto",
"firedragon1989", "florian0_", "gatzbyte", "gengartrainer",
"goldlightning1683", "haplesss", "hashtag_save_rick_gastly1",
"helex_bless_me", "helix_life", "helix_love", "herax1", "herbertderps",
"hyperbolejones", "insaneblur777", "ionface", "jericho_441", "jobuu",
"jomafro", "katiesnumber1fan", "kezberg", "kf1992", "kingnikon",
"lakwegjlahjfl", "lechanceux100", "legendarybook", "lelouch24r",
"lemortede", "leondtv", "lordsabio", "manudu12", "mathiass44", "menjabin1",
"metsfan28", "meziel", "milchmaeuse", "misaomisao", "moonb4se",
"moosefisher", "mrspaghetti12", "mtwill33", "mugwhump", "nanaki404",
"natebluehooves", "nizarkury", "nothrend", "nyphus", "obito86", "ollj",
"otrotwitch", "pct89", "peixe_alpinista", "pikaballz", "pokemon123fan",
"pokemonandpot", "pokermen69", "predatt0r", "presidentpotato",
"pudels_kern", "r3dcarp3t", "rdms18", "residentialcat",
"rickgastlyrickgastlyrick1", "rickgastlyrickgastlyrick2",
"rickgastlyrickgastlyrick3", "rickgastlyrickgastlyrick4", "rotcha",
"runxesclamation", "sabbas88", "sakitoshi", "scribblygooks", "seesil",
"slyzem", "smurfpopulation", "snailix", "stayclosa", "stealthbears",
"stevo5000x", "supergandhi64", "suppi88", "swizzerch", "tachyg",
"teamvistatech", "thatawesom3cookie", "thegoldencat",
"thewanderingdelusion", "twitchplayscrystalversion", "upup199", "uzumy12",
"valderek", "vectro_123", "w______________w", "wolfcraft7000",
"xplicittyrant", "xreactionsx", "xxquinleyxx", "zectra", "zyriss"
];
$.each(botList, function () {
botHashSet[$(this)] = 1;
});
}
function fixChatScroll() {
if (CurrentChat && CurrentChat.currently_scrolling) {
CurrentChat.scroll_chat();
}
}
function processComment() {
var row, messageElem, message, name;
row = $(this);
messageElem = row.find('.chat_line');
message = messageElem.html();
name = row.data('sender');
if ((name && botHashSet[name]) || (settings.hideInputs && message && message.match(inputRegex))) {
row.parent().prepend(this);
} else {
row.show();
}
if (changeMessages && message) {
if (settings.hideSpam) {
message = message.replace(dupeRegex, '$1');
}
if (settings.libraryMode) {
message = message.replace(upperRegex, function (s) {
return s[0] + s.slice(1).toLowerCase();
});
}
messageElem.html(message);
}
row.addClass('handled');
}
setInterval(function () {
$('#chat_line_list li:not(.handled)').each(processComment);
fixChatScroll();
}, settings.interval);
$("<style>#chat_line_list li{display:none}</style>").appendTo("head");
}(jQuery, userSettings));
You'll see near the top that there's a section for user settings where you can configure how the script behaves. There's a comment briefly describing each setting, but I'll explain them individually:
interval: 500
Because there doesn't seem to be a way to hook directly into the push event when Twitch adds a chat message, the script uses a polling system: the interval is how often the script updates the chat (500 milliseconds by default). Because the script hides all incoming messages and then reveals valid ones after processing, there is no visual issue of seeing messages get actively removed regardless of the value you set here. Chrome's JavaScript is much more optimized than Firefox's, so if you're using the former you can get away with a lower interval than if you're using the latter. Even on Chrome, though, I wouldn't recommend going below 100ms if you have all of the filter options enabled.
hideBots: true
I had a script running for about 20 hours that would detect users in the chat that would say the exact same message (ignoring the game inputs like start/down/a/b/etc) at least 5 times in a row without saying anything else. This resulted in 126 unique accounts that are spamming the chat at given intervals. If hideBots is set to true, then any chat message sent by these blacklisted accounts will be hidden.
hideInputs: true
This is probably the most important feature of the script. It filters out all chat messages that are just game inputs (start, select, a, b, up, down, left, right, anarchy, democracy, wait, [command]0-9, and combinations). If you tested out the script I posted earlier, this setting is doing the same work as that.
hideSpam: true
This setting will trim down messages that spam a message. For example, if some user says "praise helix praise helix praise helix praise helix praise helix" then you would only see them say "praise helix" as the message. This is pretty useful considering a good number of people spam like this to increase the chance their message gets seen in what is normally a fast-moving chat.
libraryMode: true
This setting will change a lot of all-caps messages to appear in regular casing. For example, if some user says "PRAISE THE HELIX FOSSIL" then you would see them say "Praise the helix fossil" as the message. There are a surprising number of users that talk in all caps, perhaps because it helps distinguish from the all-lowercase game input commands, or maybe because the chat is so "loud" (in the sense that it's busy) that they feel the need to shout to be heard. Regardless, this setting can be nice to have activated as well.
Let me know if there are any significant issues with the above. I wrote it so that both
GreaseMonkey (for Firefox) and
TamperMonkey (for Chrome) would accept it, so you can plug it in as a userscript on your browser of choice.
The script itself uses jQuery (which Twitch uses already) and is JSLint validated. I'm open to suggestions on changes/improvements/features for the script as well, and I'll answer any questions regarding the JS code.