import configparser import logging import os import re import string import dateutil.parser import irc.bot import requests config = configparser.ConfigParser() config.read('settings.cfg') log = logging.getLogger('irc.client') log.addHandler(logging.StreamHandler()) if os.getenv('DEBUG', False): log.setLevel(logging.DEBUG) QUOTE_ADDED_PATTERN = re.compile(r'''^ (?P.+)\s+-->\s+ Sweet!\s+Thanks\s+for\s+the\s+quote!\s+ \#(?P\d+):\s+ "(?P.+)"\s+ \[(?P.+)\]\s+ \[(?P.+)\]$''', re.VERBOSE) # TODO: quote_edited, quote_removed class TwitchBot(irc.bot.SingleServerIRCBot): def __init__(self): self.actions = [ (re.compile(r'^!lastquote$'), self.last_quote), (re.compile(r'^!findquote\s+(?P")?(?P.+)(?(q)")$'), self.find_quote), (QUOTE_ADDED_PATTERN, self.add_quote), ] self.server = config['IRC'].get('server', 'irc.chat.twitch.tv') self.port = config['IRC'].getint('port', 6667) self.nickname = config['IRC'].get('nickname') self.channel = '#{0}'.format(config['IRC'].get('channel')) self.token = config['Twitch'].get('token') self.api_url = config['Quotes'].get('api_url') self.api_key = config['Quotes'].get('api_key') print('Connecting to {0}:{1}'.format(self.server, self.port)) super(TwitchBot, self).__init__([(self.server, self.port, self.token)], self.nickname, self.nickname) def on_welcome(self, connection, event): connection.cap('REQ', ':twitch.tv/membership') connection.cap('REQ', ':twitch.tv/tags') connection.cap('REQ', ':twitch.tv/commands') print('Joining {0}'.format(self.channel)) connection.join(self.channel) def on_join(self, connection, event): print('Joined {0}'.format(event.target)) def on_pubmsg(self, connection, event): self.process_message(connection, event) def on_whisper(self, connection, event): self.process_message(connection, event) def process_message(self, connection, event): sources = [t['value'] for t in event.tags if t['key'] == 'display-name'] source = sources.pop() message = ''.join([c for c in event.arguments[0] if c in string.printable]) for pattern, action in self.actions: m = pattern.match(message) if m: action(connection, source, **m.groupdict()) def get(self, params): r = requests.get('{0}/quotes'.format(self.api_url), params=params) r.raise_for_status() return r.json() def post(self, data): r = requests.post('{0}/quotes'.format(self.api_url), data=data, headers={'X-Quotes-API-Key': self.api_key}) r.raise_for_status() return r.json() def delete(self): r = requests.post('{0}/quotes'.format(self.api_url), headers={'X-Quotes-API-Key': self.api_key}) r.raise_for_status() return r.json() def last_quote(self, connection, source, **kwargs): try: quotes = self.get(dict( sort_by='id', sort_order='desc', page_size=1)) quote = quotes[0] except (requests.exceptions.HTTPError, IndexError): msg = 'Sorry @{0}, no quotes found'.format(source) else: msg = '!quote {0}'.format(quote['id']) connection.privmsg(self.channel, msg) def find_quote(self, connection, source, filter, **kwargs): if len(filter) < 3: msg = 'Sorry @{0}, the search phrase is too short'.format(source) connection.privmsg(self.channel, msg) return try: quotes = self.get(dict( filter=filter, sort_by='id', sort_order='desc', page_size=1)) quote = quotes[0] except (requests.exceptions.HTTPError, IndexError): msg = 'Sorry @{0}, no quotes found'.format(source) else: msg = '!quote {0}'.format(quote['id']) connection.privmsg(self.channel, msg) def add_quote(self, connection, source, user, id, text, game, date, **kwargs): print('Adding quote {0}: {1}'.format(id, text)) try: self.post(dict( id=int(id) + 10000, # FIXME date=dateutil.parser.parse(date, dayfirst=True).date().isoformat(), game=game, text=text)) except requests.exceptions.HTTPError as e: print('Failed to add quote: ', e) def main(): bot = TwitchBot() bot.start() if __name__ == "__main__": main()