loading

In this tutorial, you'll implement a bot that moderates the chat for a channel on Twitch.tv. The bot will be able to connect to the Twitch IRC server, read the channel chat, search for unwanted messages and spam, and timeout or ban the user who sent the message.

Required Resources

  • A basic understanding of Python. I use Python 3 in this tutorial, but Python 2 is similar enough that the tutorial can be easily translated.
  • A Python installation. You'll need this to run the bot.
  • A separate Twitch.tv account. You should not use your main account, as incorrectly implementing the bot can cause you to be (temporarily) banned.

Step 1: Create a Configuration Module

Values that will differ between executions of the bot should be easy to view and modify. For this purpose, we'll create a configuration module that will store these values. Get your Twitch.tv OAuth token from twitchapps.com/tmi, and then create a new file in your source directory called 'cfg.py' and add these values:

# cfg.py
HOST = "irc.twitch.tv" # the Twitch IRC server
PORT = 6667 # always use port 6667!
NICK = "twitch_username" # your Twitch username, lowercase
PASS = "oauth:xxxxxxxxxxxxxxxxxxxx" # your Twitch OAuth token
CHAN = "#channel" # the channel you want to join

Step 2: Write the Network Functions

Twitch uses IRC as its chat protocol, which makes most communication trivial. Still, the code will end up much cleaner if we define some utility functions first.

We use sockets as the network abstraction for this bot. Sockets provide a very clear send-and-receive interface for network communications, so these functions won't be very complicated.

I've provided docstrings in compliance with PEP 257 which will provide brief explanation of the functions.

# bot.py
def chat(sock, msg):
"""
Send a chat message to the server.
Keyword arguments:
sock -- the socket over which to send the message
msg -- the message to be sent
"""
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg))

def ban(sock, user):
"""
Ban a user from the current channel.
Keyword arguments:
sock -- the socket over which to send the ban command
user -- the user to be banned
"""
chat(sock, ".ban {}".format(user))

def timeout(sock, user, secs=600):
"""
Time out a user for a set period of time.
Keyword arguments:
sock -- the socket over which to send the timeout command
user -- the user to be timed out
secs -- the length of the timeout in seconds (default 600)
"""
chat(sock, ".timeout {}".format(user, secs))

Step 3: Connect to the Twitch IRC Server

You'll need to get your Twitch OAuth token here in order to log in. You should send your OAuth token, your username, and the channel you wish to join (in that order) as shown below.

# bot.py

import cfg
import socket

# network functions go here

s = socket.socket()
s.connect((HOST, PORT))
s.send("PASS {}\r\n".format(PASS).encode("utf-8"))
s.send("NICK {}\r\n".format(NICK).encode("utf-8"))
s.send("JOIN {}\r\n".format(CHAN).encode("utf-8"))

Joining a channel will give us a huge amount of text and also connect us to the channel chat, so we need to handle responses from the server continually. We'll do this with an infinite loop; you can interrupt the program with CTRL-C.

while True:
response = s.recv(1024).decode("utf-8") print(response) sleep(0.1)

Sleeping for a tenth of a second is barely noticeable to humans, but it drastically decreases the CPU time of the program without decreasing performance.

Step 4: Make Sure the Server Knows You're Connected

IRC servers will "ping" your bot at regular intervals to make sure you're still connected: [PING :tmi.twitch.tv]. The bot should respond as soon as possible with [PONG :tmi.twitch.tv].

# bot.py
while True:
response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: print(response)

Step 5: Limit Your Messages to the Server

In order to prevent users from spamming commands, Twitch limits how quickly a user can send IRC messages to the server. For regular users, this limit is set at 20 messages per 30 seconds; moderators may send up to 100 messages per 30 seconds. Disobeying this limit will earn you an 8-hour ban from the IRC server.

The simple way to handle this limit is to define the maximum send rate in your configuration module:

# cfg.py
RATE = (20/30) # messages per second

and then change the sleep time to the inverse of that rate:

# bot.py
while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: print(response) sleep(1 / cfg.RATE)

Step 6: Recognize Messages to the Chat

Not all messages from the server are worthy of the bot's attention. We don't need to know who's joining or leaving the channel, and it's not very important who the other moderators are. We do, however, want to see chat messages, which look like this:

:nickname!nickname@nickname.tmi.twitch.tv PRIVMSG #channel :message

IRC's formatting of a chat message is rather complicated, so we'll use a regular expression to pick out messages that match this pattern. Import Python's regular expressions module:

# bot.py
import re

and define the pattern we're looking for.

# Make sure you prefix the quotes with an 'r'!
CHAT_MSG=re.compile(r"^:\w+!\w+@\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")

Once we've determined that this is a chat message, we can strip out most of the text, since we only need one copy of the username and their message. First, we need to pick the username out of the string. The username will be the first substring made up solely of regex word characters, which consist of alphanumeric characters and underscores. Once we find the username, we can replace the ugly prefix with just the username and a colon.

# bot.py
while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", line).group(0) # return the entire match message = CHAT_MSG.sub("", line) print(username + ": " + message) sleep(1 / cfg.RATE)

Step 7: Register Patterns and Drop the Banhammer

Once again, we'll use regex to match messages that contain unwanted patterns. The most obvious of these patterns are individual words or phrases, which can simply be typed as they are into the regex. For more complicated or variable patterns, you'll need to look into more advanced regex; this can be used to ban links, phone numbers, addresses (physical and email), and other information that follows a particular pattern.

Add a list of patterns to your config file:

# cfg.py
PATT = [
r"swear",
# ...
r"some_pattern"
]

Now, in your source file, add a loop that checks each message for the pattern you (don't) want:

# bot.py
while True: response = s.recv(1024).decode("utf-8") if response == "PING :tmi.twitch.tv\r\n": s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8")) else: username = re.search(r"\w+", line).group(0) # return the entire match message = CHAT_MSG.sub("", line) print(username + ": " + message)
for pattern in cfg.PATT:
if re.match(pattern, message):
ban(s, username)
break
sleep(1 / cfg.RATE)

Step 8: Congratulations!

You've successfully implemented a moderator bot for Twitch.tv. Of course, this tutorial only walks you through a fairly minimal implementation; in order to have functionality like that of Nightbot or Moobot, you'll have to do a bit more work. However, this bot provides a solid foundation for expansion and customization. Good luck!

<p>If you use TChat Android app, you can easily moderate while streaming https://play.google.com/store/apps/details?id=org.tchat</p>
<p>So I have the bot joining the channel, but there is a 2 minute delay (I think it's exactly 2 minutes) - and the same happens when killing python, the bot takes 2 minutes to PART. Why would this be? (I also have no responses coming in on the socket, and can't send/chat to channel.) - Thoughts?</p>
<p>The problem is there is a # sign in the name of the channel </p><p>CHAN = &quot;#channel&quot;</p><p>Then another one in the send function </p><p>sock.send(&quot;PRIVMSG #{} :{}&quot;.format(cfg.CHAN, msg))</p><p>So the message see the channel as ##channel</p><p>If you remove one of them, it works fine. </p>
<p>The <strong>real</strong> problem was that I was using git bash shell and that was causing me not to see responses - that's why I replied to myself saying that. </p><p>And using ##channel is not a problem; It's not what most people want, but it's valid on IRC - <strong>/join ##channel</strong> on IRC will not give you any errors. (You will just be in a channel called &quot;#channel&quot; instead of &quot;channel.&quot;) </p><p>In addition, this instructable TELLS you to use it, so I was not wrong. See step 1:</p><blockquote><p># cfg.py<br>...<br>CHAN = &quot;#channel&quot; # the channel you want to join</p><br></blockquote>
<p>WELP - turns out you should not run Python scripts through GitBash bash shell. This bot wasn't working right, and neither was virtualenv for python when using GitBash. smh - Okay windows cmd... I'll use you. /sigh.</p>
<p>Best way to do it is set up a little home server with a PC that's not being used. Heck my server at home is an old PC I got at a yard sale for $10. This is the best way to learn programming and how to work as a system administrator</p>
<p>Hi; </p><p>I have the following question:</p><p>my bot seems to randomly loose connection from time to time.</p><p>How can I check if I am still connected to the Twitch-channel, so that I can reconnect when necessary? (similar to pinging twitch?)</p><p>Which time-interval should I use to check my connection? every 5 seconds?</p>
<p>Hi ! Your code is fabulous, the problem I encountered is when you do the &quot;stress test&quot;, like spamming the twitch channel with message, he can't handle that much messages in a row, so at a moment, when you repeat 5 times the same command in like ... 1 second, you get something like that : <br><br>:thaod5!channel@channel.tmi.twitch.tv PRIVMSG #channel :command<br><br>Quite annoying, since he does not recognize some words in such mess, how could we possibly solve that ? <br>Ty, great work ! :-) </p>
<p>I'm having a small issue with my version of what you did</p><p><a href="http://pastebin.com/QAz7MV9S" rel="nofollow">http://pastebin.com/QAz7MV9S</a> - The Python Scripts</p><p>this is a screenshot of the error and i can't find where you defined Line or what the filler is supposed to be, i'm quite new to python.</p><p><a href="https://gyazo.com/e690df99835ed0e3da56f04d363fbe84" rel="nofollow">https://gyazo.com/e690df99835ed0e3da56f04d363fbe84</a> </p>
<p>Figured it out, just change &quot;line&quot; to &quot;response&quot;.</p>
<p>Thanks for this great start! Now I can focus on the important bits.</p>
<p>Awesome bot, I bet it can be really helpful! Welcome to instructables!</p>

About This Instructable

63,895views

12favorites

More by cormac-obrien:Twitch.tv Moderator Bot 
Add instructable to: