Last active 1652358075

Python IRC bot for automatically retrieving Twitch stream status

Revision 8d508dd9229685b4e40036a625786a001c3dadfb

irctwitch.py Raw
1# Twitch IRC status autoupdate
2# Create an empty file called config.yml in the same directory, containing:
3# host: irc.quakenet.org
4# port: 6667
5# channels: ["#channel", "#anotherchannel"]
6# nspass: "nickserv/Q password"
7# password: "server password for BNC or private server"
8# twitch: "channelname"
9
10import requests
11import yaml
12from HTMLParser import HTMLParser
13from sys import stdout
14
15from twisted.internet import reactor, task, protocol
16from twisted.python import log
17from twisted.words.protocols import irc
18from twisted.application import internet, service
19
20with open('config.yml') as f:
21 config = yaml.load(f.read())
22HOST, PORT = config['host'], config['port']
23
24
25def munge(inp):
26 # Prevents highlight notification in most clients
27 return inp[0] + u"\u200b" + inp[1:]
28
29
30class TwitchProtocol(irc.IRCClient):
31 password = config["password"] if "password" in config else None
32 nickname = 'Twitch'
33 username = 'Twitch'
34 versionName = 'Twitch'
35 versionNum = 'v1.0'
36 realname = 'by blha303. https://gist.github.com/blha303'
37 loopcall = None
38 status = False
39
40
41 def signedOn(self):
42 for channel in self.factory.channels:
43 self.join(channel)
44 #Quakenet
45 self._send_message("auth %s %s" % (self.nickname, config["nspass"]), "Q")
46 #Nickserv
47 self._send_message("identify %s %s" % (self.nickname, config["nspass"]), "NickServ")
48 #Nickserv that doesn't support specifying a nickname
49 self._send_message("identify %s" % config["nspass"], "NickServ")
50
51 def restartloop(reason):
52 reason.printTraceback()
53 print "Loop crashed: " + reason.getErrorMessage()
54 self.loopcall.start(5.0).addErrback(restartloop)
55 self.loopcall = task.LoopingCall(self.getTwitchStatus)
56 self.loopcall.start(5.0).addErrback(restartloop)
57
58 def getTwitchStatus(self):
59 channel = config["twitch"]
60 data = requests.get("http://api.justin.tv/api/stream/list.json?channel=" + channel).json()
61 if data and not self.status:
62 fmt = "{}: {} {} ({})"
63 self.status = True
64 title = data[0]['title']
65 playing = ("playing " + data[0]['meta_game']) if "meta_game" in data[0] else ""
66 viewers = "\x033\x02Online now!\x02\x0f " + str(data[0]["channel_count"]) + " viewer"
67 print viewers
68 viewers = viewers + "s" if not " 1 view" in viewers else viewers
69 print viewers
70 h = HTMLParser()
71 for ch in self.factory.channels:
72 self._send_message(h.unescape(fmt.format(title, munge(channel), playing, viewers)), ch)
73 elif not data and self.status:
74 self.status = False
75 for ch in self.factory.channels:
76 self._send_message("%s is now offline." % channel, ch)
77
78
79 def privmsg(self, user, channel, message):
80 nick, _, host = user.partition('!')
81 print "<%s> %s" % (nick, message)
82
83
84 def _send_message(self, msg, target, nick=None):
85 if nick:
86 msg = '%s, %s' % (nick, msg)
87 self.msg(target, msg)
88 print "<%s> %s" % (self.nickname, msg)
89
90
91class TwitchFactory(protocol.ReconnectingClientFactory):
92 protocol = TwitchProtocol
93 channels = config["channels"]
94
95if __name__ == '__main__':
96 reactor.connectTCP(HOST, PORT, TwitchFactory())
97 log.startLogging(stdout)
98 reactor.run()
99
100elif __name__ == '__builtin__':
101 application = service.Application('Twitch')
102 ircService = internet.TCPClient(HOST, PORT, TwitchFactory())
103 ircService.setServiceParent(application)
104