diff --git a/lolbot.py b/lolbot.py index 9d22ff2..54841a6 100644 --- a/lolbot.py +++ b/lolbot.py @@ -10,6 +10,7 @@ LOLBOT 2 from __future__ import print_function, unicode_literals import sys +import os import sqlite3 import random import time @@ -51,13 +52,13 @@ class LolBot(SingleServerIRCBot): if not self.validate_config(config): sys.exit(1) + self.config = config (server, port, channel, nickname, database) = ( config['irc.server'], config['irc.port'], config['irc.channel'], config['irc.nickname'], - config['db.file'], - ) + config['db.file']) debug("Instantiating SingleServerIRCBot") irc.client.ServerConnection.buffer_class = irc.buffer.LenientDecodingLineBuffer @@ -81,7 +82,7 @@ class LolBot(SingleServerIRCBot): self.dbengine = create_engine('sqlite+pysqlite://', creator=self._get_connection) Model.metadata.bind = self.dbengine Model.metadata.create_all() - self.db_session = sessionmaker(bind=self.dbengine) + self.get_db = sessionmaker(bind=self.dbengine) self.helptext = "Keeps a list of URLs. Commands: list [n|x-y] - prints the last 10 URLs (or n URLs, or x through y); - adds the URL to the list; help - this message." debug("Exiting lolbot constructor") @@ -93,17 +94,48 @@ class LolBot(SingleServerIRCBot): debug("Creating SQLAlchemy connection") return connection + @property + def nickname(self): + return self.connection.get_nickname() + + def say_public(self, text): + """ + Say text in the public channel for all to see. + """ + self.connection.privmsg(self.channel, text) + self.log_event(self.nickname, text) + + def say_private(self, nick, text): + """ + Say text in a private message to nick. + """ + self.connection.privmsg(nick, text) + + def reply(self, text, to_private=None): + """ + Say text in either public channel or a private message (if to_private + supplied). + """ + if to_private is not None: + self.say_private(to_private, text) + else: + self.say_public(text) + def on_nicknameinuse(self, connection, event): - nick = connection.get_nickname() - debug("Nick '%s' in use, trying '%s_'" % (nick, nick)) - connection.nick(nick + "_") + debug("Nick '%s' in use, trying '%s_'" % (self.nickname, self.nickname)) + connection.nick(self.nickname + "_") def on_welcome(self, connection, event): - debug("Joining channel '%s'" % self.channel) + debug("Joining channel '%s' as %s" % (self.channel, self.nickname)) connection.join(self.channel) def on_privmsg(self, connection, event): - self.do_command(event, event.arguments[0]) + """ + Handle a /msg from a user. + Handle commands addressed to the bot. + """ + message = event.arguments[0] + self.do_command(event, message) def on_pubmsg(self, connection, event): """ @@ -111,19 +143,61 @@ class LolBot(SingleServerIRCBot): Handle commands addressed to the bot. If there's a question, see if it's been answered. """ + + # Handle bot commands if addressed by nick or using ! shortcut. try: - (nick, message) = event.arguments[0].split(":", 1) - # handle command, if addressed + (nick, message) = event.arguments[0].split(": ", 1) if irc.strings.lower(nick) == irc.strings.lower(self.connection.get_nickname()): self.do_command(event, message.strip()) except ValueError: message = event.arguments[0] nick = event.source.nick + if message.startswith('!'): + self.do_command(event, message.lstrip('!')) - # deal with MoxQuizz question + # Log it. + self.log_event(nick, message) + + # Deal with MoxQuizz question. if self.quiz: self.handle_quiz(nick, message) + # Record URLs. + words = message.split(" ") + for w in words: + if w.startswith('http://') or w.startswith('https://'): + title = self.save_url(nick, w) + if title is False: + self.say_public("Failed to record URL, or no title found.") + else: + self.say_public("URL added. %s" % title) + + def save_url(self, nickname, url): + title = False + try: + db = self.get_db() + if not db.query(Url).filter(Url.url == url).count(): + theurl = Url(nickname, url) + db.add(theurl) + db.commit() + else: + theurl = db.query(Url).filter(Url.url == url).one() + print(theurl) + title = theurl.title + except Exception as ex: + print("Exception caught saving URL: %s" % ex) + return title + + def log_event(self, nick, text): + try: + entry = Log(nick, text) + db = self.get_db() + db.add(entry) + db.commit() + print(entry) + except Exception as ex: + print("Exception caught logging event: %s" % ex) + def start_quiz(self, nick): self.quiz = 0 self.quiz_scores = dict() @@ -233,7 +307,7 @@ class LolBot(SingleServerIRCBot): self.quiz_get_next() elif cmd.startswith('urls') or cmd.startswith('list'): - db = self.db_session() + db = self.get_db() try: (listcmd, n) = cmd.split(" ", 1) except ValueError: @@ -326,7 +400,7 @@ class LolBot(SingleServerIRCBot): # Get configuration from a file. if option in ('-c', '--config'): - config = load_config(value) + config = LolBot.load_config(value) break # Individually specified settings. diff --git a/models.py b/models.py index fe0511c..61e8d2a 100644 --- a/models.py +++ b/models.py @@ -66,11 +66,12 @@ class Url(Model): # populate the title from the URL if not given. if title is None: - try: - dom = BeautifulSoup(requests.get(self.url), 'html.parser') + r = requests.get(url) + if r.status_code == 200: + dom = BeautifulSoup(r.content, 'html.parser') self.title = dom.title.string - except Exception: - self.title = '' + else: + self.title = "Error: HTTP %s" % r.status_code def __repr__(self): if not self.title: