I was exploring Twitch’s IRC chat the other day and realized that it wasn't possible (as far as my knowledgement went back than) to check the chat without logging in via IRC. But I noted that if you join a channel on Twitch, without being logged in, the chat is readable in the web client. So I was curious about how that worked.

So I started looking into it, First I started a virtual machine and ran Wireshark (an awesome network sniffer). Then I loaded my own channel on the virtual machine on which I wasn't logged in to Twitch. The reason that I used a virtual machine is that my main machine has a lot of trafific which makes it harder for me to find the packets I need. After that I loaded the chat on my physical machine Where I was logged in to Twitch. So to made it myself as easy as possible, I sent a message “$test_unique_message” (Wireshark was already sniffing packets when I loaded the page, that is essential, else Wireshark wouldn't have recorded all packets from the start of loading the page).

So I wanted to find all packets that were sent between my virtual machine and Twitch’s IRC server. So I started searching for “test_unique_message” so I knew which IP address I had to look up. I set the options to search for a “String” in “Packet bytes” (as it was text in a packet).

But because Wireshark said “Continuation Data” it meant that it was a connection that was being kept alive, or at least, it wasn't the first message in the stream. That probably meant that ALL the IRC messages were probably in the same connection, so I used Wireshark’s feature “Follow TCP Stream” and (sadly enough, maybe to little of a challenge) there it was…

PASS blah

Nick justinfan332755

And it was easy to guess that the password was probably the same for all the justinfan accounts, which number they had probably didn't matter either (later on I tested random passwords, that also worked... but I recommend using the password blah, just to stay undercover and act like you just used the web client). So I just tried logging on to the IRC server with a random user: justinfan55218, password:blah… and I got in. Sure, you still can’t talk in the chat (well, technically you can, but all messages from the username justinfan won’t get forwarded/shown to other users), but with this you can create a “silent bot” (A bot that monitors the chat without showing that there is anyone, as justinfans also won’t get listed in the viewers section).

Because of earlier work on a bot for Twitch, I knew that when you pass TWITCHCLIENT 2 to the IRC server you also receive messages that someone has subscribed (which is what i needed that bot for). What the difference is between TWITCHCLIENT 2 and 4, I can’t tell… for more info about TWITCHCLIENT see: http://discuss.dev.twitch.tv/t/accessing-chat-information/307

 

Here is a Python script I wrote that logs all messages in 3 chats to their own file, so everything sent in rikels will be written to rikels.txt and eveything sent in rikels1 will be written to rikels1.txt. (I’m not a programmer, so there are probably a few things that could be more efficient).

import socket
import time
from random import random
import re


Twitch_user = "justinfan{random}".format(random=int(random()*9999999))
Twitch_pass = "blah"
Twitch_channel = ["rikels","rikels1","rikels2"]
chat_log_path = "/home/rikels/Twitch/"
sub = False
sub_time = None


def connect():
    irc = socket.socket()
    irc.connect(("irc.twitch.tv", 6667))
    irc.send("PASS {passw}\r\n".format(passw=Twitch_pass))
    irc.send("NICK {user}\r\n".format(user = Twitch_user))
    irc.send("USER {user} 199.9.253.199 bla :{user}\r\n".format(user=Twitch_user))
    irc.send("JOIN #{users}\r\n".format(users=",#".join(Twitch_channel)))
    #making sure we receive info that the subscribermode was turned off/on with "TWITCHCLIENT 2,3,4"
    #by enabling this, you'll lose the join/part messages
    # irc.send("TWITCHCLIENT 4\r\n")
    return(irc)

irc = connect()

while(True):
    #buff as in buffer, but that is a registered python word/function
    buff = irc.recv(8192)
    buff = buff.split("\r\n")
    for buf in buff[:-1]:
        #to keep the connection alive, we have to reply to the ping
        #Twitch terminates the connection if it doesn't receive a reply after 3 pings
        if "PING" in buf:
            print("received ping")
            buf = "PONG tmi.twitch.tv\r\n"
            irc.send(buf)
        if buf == ":tmi.twitch.tv RECONNECT":
            print("received reconnect :S?")
            irc = connect()
            #opening a file with a+ means append, and create if it doesn't exist
            try:
                extracted_info = re.match(":(\w+)!\w+@\w+.tmi.twitch.tv PRIVMSG #(\w+) :(.*)",buf)
                with open(chat_log_path+extracted_info.group(2)+".txt","a+") as chat_log:
                    chat_log.write("{time}{user}:{message}\r\n".format(time=int(time.time()),user=extracted_info.group(1),message=extracted_info.group(3)))
            except:
                try:
                    with open(chat_log_path+"Twitch_logger.txt","a+") as chat_log:
                        chat_log.write("{time}{message}\r\n".format(time=int(time.time()),message=buf))
                #if there is an error, this will print exactly what went wrong, and just continue if possible, because of the while loop
                #Without Try/Except the script would stop completely
                except Exception as error:
                    print(error)