From 1b71e73757936161e4363e45b74c6bd28d4e519a Mon Sep 17 00:00:00 2001 From: iou1name Date: Tue, 7 Jan 2020 18:58:19 -0500 Subject: [PATCH] refactored trigger --- bot.py | 22 +++--- modules/admin.py | 39 +++++----- modules/adminchannel.py | 32 +++++---- modules/announce.py | 10 +-- modules/ascii.py | 4 +- modules/away.py | 8 +-- modules/banhe.py | 7 +- modules/calc.py | 9 ++- modules/countdown.py | 6 +- modules/crypto.py | 4 +- modules/currency.py | 19 +++-- modules/dice.py | 17 ++--- modules/echo.py | 4 +- modules/grog.py | 10 +-- modules/hangman.py | 14 ++-- modules/help.py | 4 +- modules/isup.py | 6 +- modules/lmgtfy.py | 4 +- modules/minecraft.py | 2 +- modules/movie.py | 13 ++-- modules/privilege.py | 4 +- modules/rand.py | 25 ++++--- modules/reload.py | 14 ++-- modules/remind.py | 67 ++++++------------ modules/resistor.py | 4 +- modules/rundown.py | 7 +- modules/scramble.py | 6 +- modules/sed.py | 153 +++++++++++++++------------------------- modules/seen.py | 8 +-- modules/slur.py | 2 +- modules/spellcheck.py | 4 +- modules/tell.py | 8 ++- modules/tld.py | 6 +- modules/topic.py | 4 +- modules/translate.py | 8 +-- modules/unicode_info.py | 4 +- modules/units.py | 6 +- modules/uptime.py | 22 +++--- modules/url.py | 4 +- modules/watcher.py | 12 ++-- modules/weather.py | 8 ++- modules/wikipedia.py | 4 +- modules/wiktionary.py | 4 +- modules/willilike.py | 2 +- modules/wolfram.py | 4 +- modules/xkcd.py | 4 +- trigger.py | 110 ++--------------------------- 47 files changed, 297 insertions(+), 441 deletions(-) diff --git a/bot.py b/bot.py index c28b82d..ae9d439 100755 --- a/bot.py +++ b/bot.py @@ -166,10 +166,10 @@ class Fulvia(irc.IRCClient): self.commands.pop(command) if func.hook: - self._hooks.remove(func.__name__) + self._hooks.remove(func) if func.rate or func.channel_rate or func.global_rate: - self._times.pop(func.__name__) + self._times.pop(func) if hasattr(func, 'url_callback'): for url in func.url_callback: @@ -253,26 +253,26 @@ class Fulvia(irc.IRCClient): funcs += self._hooks for func in funcs: - trigger = Trigger(user, channel, message, "PRIVMSG") + trigger = Trigger(user, channel, message) bot = FulviaWrapper(self, trigger) if func.rate: - t = self._times[func_name].get(trigger.nick, 0) + t = self._times[func.__name__].get(trigger.nick, 0) if time.time() - t < func.rate and not trigger.admin: return - self._times[func_name][trigger.nick] = time.time() + self._times[func.__name__][trigger.nick] = time.time() if func.channel_rate: - t = self._times[func_name].get(trigger.channel, 0) + t = self._times[func.__name__].get(trigger.channel, 0) if time.time() - t < func.channel_rate and not trigger.admin: return - self._times[func_name][trigger.channel] = time.time() + self._times[func.__name__][trigger.channel] = time.time() if func.global_rate: - t = self._times[func_name].get("global", 0) + t = self._times[func.__name__].get("global", 0) if time.time() - t < func.channel_rate and not trigger.admin: return - self._times[func_name]["global"] = time.time() + self._times[func.__name__]["global"] = time.time() if func.thread == True: t = threading.Thread(target=self.call,args=(func, bot, trigger)) @@ -394,9 +394,9 @@ class Fulvia(irc.IRCClient): self.channels[channel].users[nick] = new_user for func in self._user_joined: - trigger = Trigger(user, channel, f"{user} has joined", "PRIVMSG") + trigger = Trigger(user, channel, f"{user} has joined") bot = FulviaWrapper(self, trigger) - t = threading.Thread(target=self.call,args=(func, bot, trigger)) + t = threading.Thread(target=self.call, args=(func, bot, trigger)) t.start() diff --git a/modules/admin.py b/modules/admin.py index f506149..d405c9b 100755 --- a/modules/admin.py +++ b/modules/admin.py @@ -10,7 +10,8 @@ import module @module.example('.join #example or .join #example key') def join(bot, trigger): """Join the specified channel. This is an admin-only command.""" - channel, key = trigger.group(3), trigger.group(4) + channel = trigger.args[1] if len(trigger.args) >= 2 else None + key = trigger.args[2] if len(trigger.args) >= 3 else None if not channel: return elif not key: @@ -24,7 +25,14 @@ def join(bot, trigger): @module.example('.part #example') def part(bot, trigger): """Part the specified channel. This is an admin-only command.""" - channel, _, part_msg = trigger.group(2).partition(' ') + if len(trigger.args) < 2: + return + channel = trigger.args[1] + if len(trigger.args) >= 3: + part_msg = ' '.join(trigger.args[2:]) + else: + part_msg = None + if not channel.startswith("#"): part_msg = channel channel = "" @@ -40,8 +48,9 @@ def part(bot, trigger): @module.commands('quit') def quit(bot, trigger): """Quit from the server. This is an owner-only command.""" - quit_message = trigger.group(2) - if not quit_message: + if len(trigger.args) >= 2: + quit_message = ' '.join(trigger.args[1:]) + else: quit_message = f"Quitting on command from {trigger.nick}" bot.quit(quit_message) @@ -54,13 +63,10 @@ def msg(bot, trigger): """ Send a message to a given channel or nick. Can only be done by an admin. """ - if trigger.group(2) is None: - return - - channel, _, message = trigger.group(2).partition(' ') - message = message.strip() - if not channel or not message: + if len(trigger.args) < 3: return + channel = trigger.args[1] + message = ' '.join(trigger.args[2:]) bot.msg(channel, message) @@ -73,13 +79,10 @@ def me(bot, trigger): Send an ACTION (/me) to a given channel or nick. Can only be done by an admin. """ - if trigger.group(2) is None: - return - - channel, _, action = trigger.group(2).partition(' ') - action = action.strip() - if not channel or not action: + if len(trigger.args) < 3: return + channel = trigger.args[1] + action = ' '.join(trigger.args[2:]) # msg = '\x01ACTION %s\x01' % action bot.describe(channel, action) @@ -90,6 +93,8 @@ def me(bot, trigger): @module.example(".mode +B") def self_mode(bot, trigger): """Set a user mode on Fulvia. Can only be done in privmsg by an admin.""" - mode = trigger.group(3) + if len(trigger.args) < 2: + return + mode = trigger.args[1] add_mode = mode.startswith("+") bot.mode(bot.nickname, add_mode, mode) diff --git a/modules/adminchannel.py b/modules/adminchannel.py index 92de285..11e04d8 100755 --- a/modules/adminchannel.py +++ b/modules/adminchannel.py @@ -21,11 +21,12 @@ def kick(bot, trigger): """ if bot.channels[trigger.channel].users[bot.nick].op_level not in op: return bot.reply("I'm not a channel operator!") - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Who do you want me to kick?") - - target, _, reason = trigger.group(2).partition(" ") - if not reason: + target = trigger.args[1] + if len(trigger.args) >= 3: + reason = ' '.join(trigger.args[2:]) + else: reason = "Stop doing the bad." if target == bot.nick: @@ -45,10 +46,10 @@ def ban(bot, trigger): """ if bot.channels[trigger.channel].users[bot.nick].op_level not in op: return bot.reply("I'm not a channel operator!") - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Who do you want me to ban?") - banmask = configureHostMask(trigger.group(2)) + banmask = configureHostMask(trigger.args[1]) bot.mode(trigger.channel, True, "b", mask=banmask) @@ -63,10 +64,10 @@ def unban(bot, trigger): """ if bot.channels[trigger.channel].users[bot.nick].op_level not in op: return bot.reply("I'm not a channel operator!") - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Who do you want me to ban?") - banmask = configureHostMask(trigger.group(2)) + banmask = configureHostMask(trigger.args[1]) bot.mode(trigger.channel, False, "b", mask=banmask) @@ -81,17 +82,18 @@ def kickban(bot, trigger): """ if bot.channels[trigger.channel].users[bot.nick].op_level not in op: return bot.reply("I'm not a channel operator!") - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Who do you want me to ban?") - - target, _, reason = trigger.group(2).partition(" ") - if not reason: + target = trigger.args[1] + if len(trigger.args) >= 3: + reason = ' '.join(trigger.args[2:]) + else: reason = "Stop doing the bad." if target == bot.nick: return bot.reply("I can't let you do that.") - banmask = configureHostMask(trigger.group(2).strip()) + banmask = configureHostMask(trigger.args[1]) bot.mode(trigger.channel, False, "b", mask=banmask) bot.kick(trigger.channel, target, reason) @@ -107,7 +109,7 @@ def settopic(bot, trigger): """ if bot.channels[trigger.channel].users[bot.nick].op_level not in op: return bot.reply("I'm not a channel operator!") - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("What do you want the topic set to?") - bot.topic(trigger.channel, trigger.group(2).strip()) + bot.topic(trigger.channel, ' '.join(trigger.args[1:])) diff --git a/modules/announce.py b/modules/announce.py index 117118c..efe4a58 100755 --- a/modules/announce.py +++ b/modules/announce.py @@ -2,18 +2,18 @@ """ Sends a message to all channels the bot is currently in. """ -from module import commands, example +from module import commands, example, require_admin +@require_admin @commands('announce') @example('.announce Some important message here') def announce(bot, trigger): """ Send an announcement to all channels the bot is in. """ - if not trigger.admin: - bot.reply("Sorry, I can't let you do that") - return + if len(trigger.args) < 2: + return bot.reply("What message?") for channel in bot.channels.keys(): - bot.msg(channel, f"[ANNOUNCEMENT] {trigger.group(2)}") + bot.msg(channel, f"[ANNOUNCEMENT] {trigger.args[1]}") bot.reply('Announce complete.') diff --git a/modules/ascii.py b/modules/ascii.py index c76ab44..b3e561a 100755 --- a/modules/ascii.py +++ b/modules/ascii.py @@ -233,7 +233,7 @@ def ascii(bot, trigger): """ Downloads an image and converts it to ascii. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.msg() parser = argparse.ArgumentParser(add_help=False) parser.add_argument("imagePath") @@ -243,7 +243,7 @@ def ascii(bot, trigger): parser.add_argument("-B", "--brail2", action="store_true") parser.add_argument("-a", "--animated", action="store_true") parser.add_argument("-h", "--help", action="store_true") - args = parser.parse_args(trigger.group(2).split()) + args = parser.parse_args(trigger.args[1:]) if args.help: return bot.msg(parser.print_help()) diff --git a/modules/away.py b/modules/away.py index 13c69d9..34b6f61 100755 --- a/modules/away.py +++ b/modules/away.py @@ -16,10 +16,10 @@ def away(bot, trigger): """ Stores in the user's name and away message in memory. """ - if not trigger.group(2): + if len(trigger.args) < 2: bot.memory['away'][trigger.nick] = "" else: - bot.memory['away'][trigger.nick] = trigger.group(2) + bot.memory['away'][trigger.nick] = ' '.join(trigger.args[1:]) @hook(True) @@ -27,7 +27,7 @@ def message(bot, trigger): """ If an away users name is said, print their away message. """ - name = trigger.group(1) + name = trigger.args[0] if name.endswith(":") or name.endswith(","): name = name[:-1] if name in bot.memory["away"]: @@ -41,6 +41,6 @@ def notAway(bot, trigger): """ If an away user says something, remove them from the away dict. """ - if not trigger.group(0).startswith(".away"): + if not trigger.args[0] == ".away": if trigger.nick in bot.memory["away"]: bot.memory["away"].pop(trigger.nick) diff --git a/modules/banhe.py b/modules/banhe.py index 1d9fb13..0c829dd 100755 --- a/modules/banhe.py +++ b/modules/banhe.py @@ -16,7 +16,8 @@ def banhe(bot, trigger): Bans he for a set period of time. Admins may set the period of time, non-admins only get 20 second bans. """ - banhee, period = trigger.group(3), trigger.group(4) + banhee = trigger.args[1] if len(trigger.args) >= 2 else '' + period = trigger.args[2] if len(trigger.args) >= 3 else '' if not trigger.admin: period = 20 @@ -24,7 +25,7 @@ def banhe(bot, trigger): conv = {'s':1, 'm':60, 'h':3600, 'd':86400} try: period = conv[period[-1]] * int(period[:-1]) - except (KeyError, ValueError, TypeError): + except (KeyError, ValueError, TypeError, IndexError): period = 0 banmask = configureHostMask(banhee) @@ -47,7 +48,7 @@ def banheall(bot, trigger): """ Ban them all, Johnny. """ - period = trigger.group(2) + period = trigger.args[1] if len(trigger.args) >= 2 else '20s' conv = {'s':1, 'm':60, 'h':3600, 'd':86400} try: period = conv[period[-1]] * int(period[:-1]) diff --git a/modules/calc.py b/modules/calc.py index 29d1d1e..b575797 100755 --- a/modules/calc.py +++ b/modules/calc.py @@ -15,10 +15,9 @@ BASE_TUMBOLIA_URI = 'https://tumbolia-two.appspot.com/' @example('.c 5 + 3', '8') def c(bot, trigger): """Evaluate some calculation.""" - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Nothing to calculate.") - # Account for the silly non-Anglophones and their silly radix point. - eqn = trigger.group(2).replace(',', '.') + eqn = ' '.join(trigger.args[1:]) try: result = eval_equation(eqn) result = "{:.10g}".format(result) @@ -33,10 +32,10 @@ def c(bot, trigger): @example('.py len([1,2,3])', '3') def py(bot, trigger): """Evaluate a Python expression.""" - if not trigger.group(2): + if len(trigger.args) < 2: return bot.msg("Need an expression to evaluate") - query = trigger.group(2) + query = trigger.args[1] uri = BASE_TUMBOLIA_URI + 'py/' res = requests.get(uri + query) res.raise_for_status() diff --git a/modules/countdown.py b/modules/countdown.py index f1f8745..460872c 100755 --- a/modules/countdown.py +++ b/modules/countdown.py @@ -14,9 +14,9 @@ def generic_countdown(bot, trigger): """ .countdown - displays a countdown to a given date. """ - text = trigger.group(2) - if not text: + if len(trigger.args) < 2: return bot.msg("Please use correct format: .countdown 2012 12 21") + text = trigger.args[1] text = text.split() if (len(text) != 3 or not text[0].isdigit() or not text[1].isdigit() @@ -28,5 +28,5 @@ def generic_countdown(bot, trigger): return bot.msg("Please use correct format: .countdown 2012 12 21") msg = relativeTime(datetime.now(), date) - msg += " until " + trigger.group(2) + msg += " until " + trigger.args[1] bot.msg(msg) diff --git a/modules/crypto.py b/modules/crypto.py index 0f12347..7216760 100644 --- a/modules/crypto.py +++ b/modules/crypto.py @@ -23,7 +23,9 @@ def crypto(bot, trigger): "key": config.coinlib_api_key, "pref": "USD", } - symbol = trigger.group(3) + if len(trigger.args) < 2: + return bot.reply("What coin?") + symbol = trigger.args[1] if symbol: params["symbol"] = symbol res = requests.get(URI + "/coin", params=params) diff --git a/modules/currency.py b/modules/currency.py index 0c2423d..6a9ece4 100755 --- a/modules/currency.py +++ b/modules/currency.py @@ -19,14 +19,12 @@ def exchange(bot, trigger): Supported currencies: https://www.exchangerate-api.com/supported-currencies """ - amount = trigger.group(3) - cur_from = trigger.group(4) - cur_to = trigger.group(5) - if cur_to == "to": - cur_to = trigger.group(6) + if len(trigger.args) < 5: + return bot.reply("Insuffcient arguments.") + amount = trigger.args[1] + cur_from = trigger.args[2] + cur_to = trigger.args[4] - if not all((amount, cur_to, cur_from)): - return bot.reply("I didn't understand that. Try: .cur 20 EUR to USD") try: amount = float(amount) except ValueError: @@ -58,10 +56,11 @@ def bitcoin(bot, trigger): Show the current bitcoin value in USD. Optional parameter allows non-USD conversion. """ - cur_to = trigger.group(3) - if not cur_to: + if len(trigger.args) < 2: cur_to = "USD" - cur_to = cur_to.upper() + else: + cur_to = trigger.args[1] + cur_to = cur_to.upper() url = BTC_URI.format(**{"CUR_TO": cur_to}) res = requests.get(url, verify=True) diff --git a/modules/dice.py b/modules/dice.py index 8827651..316f109 100755 --- a/modules/dice.py +++ b/modules/dice.py @@ -178,9 +178,9 @@ def roll(bot, trigger): # Get a list of all dice expressions, evaluate them and then replace the # expressions in the original string with the results. Replacing is done # using string formatting, so %-characters must be escaped. - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("No dice to roll.") - arg_str = trigger.group(2) + arg_str = ' '.join(trigger.args[1:]) dice_expressions = re.findall(dice_regexp, arg_str) arg_str = arg_str.replace("%", "%%") arg_str = re.sub(dice_regexp, "%s", arg_str) @@ -215,7 +215,7 @@ def roll(bot, trigger): return bot.reply("You roll %s: %s = %d" % ( - trigger.group(2), pretty_str, result)) + ' '.join(trigger.args[1:]), pretty_str, result)) @module.commands("choice", "choose") @@ -224,16 +224,17 @@ def choose(bot, trigger): """ .choice option1|option2|option3 - Makes a difficult choice easy. """ - if not trigger.group(2): - return bot.reply('I\'d choose an option, but you didn\'t give me any.') - choices = [trigger.group(2)] + if len(trigger.args) < 2: + return bot.reply("I'd choose an option, but you didn't give me any.") + msg = ' '.join(trigger.args[1:]) + choices = [msg] for delim in '|\\/,': - choices = trigger.group(2).split(delim) + choices = msg.split(delim) if len(choices) > 1: break # Use a different delimiter in the output, to prevent ambiguity. for show_delim in ',|/\\': - if show_delim not in trigger.group(2): + if show_delim not in msg: show_delim += ' ' break diff --git a/modules/echo.py b/modules/echo.py index 309b55e..183fe33 100755 --- a/modules/echo.py +++ b/modules/echo.py @@ -8,5 +8,5 @@ from module import commands, example @example('.echo balloons') def echo(bot, trigger): """Echos the given string.""" - if trigger.group(2): - bot.msg(trigger.group(2)) + if len(trigger.args) >= 2: + bot.msg(' '.join(trigger.args[1:])) diff --git a/modules/grog.py b/modules/grog.py index 17dc0a5..97f5fb8 100755 --- a/modules/grog.py +++ b/modules/grog.py @@ -18,8 +18,8 @@ def grog(bot, trigger): data = file.read().splitlines() num = None try: - num = int(trigger.group(2)) - 1 - except: + num = int(trigger.args[1]) - 1 + except (IndexError, ValueError): pass if num == None: num = random.randint(0, len(data)-1) @@ -38,11 +38,11 @@ def magic(bot, trigger): data = file.read().splitlines() num = None try: - num = int(trigger.group(2)) - 1 - except: + num = int(trigger.args[1]) - 1 + except (IndexError, ValueError): pass if num == None: num = random.randint(0, len(data)-1) if num >= len(data)-1: num = len(data)-1 - bot.msg(data[num]) \ No newline at end of file + bot.msg(data[num]) diff --git a/modules/hangman.py b/modules/hangman.py index c7a53e8..0890dc0 100755 --- a/modules/hangman.py +++ b/modules/hangman.py @@ -40,10 +40,10 @@ def hangman(bot, trigger): Plays hangman. --start [-s] to start a new game, otherwise words are taken as attempts to solve and single characters are taken as guesses. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Hang what?") - if trigger.group(3) == "--start" or trigger.group(3) == "-s": + if trigger.args[1] == "--start" or trigger.args[1] == "-s": if bot.memory["hangman"].get(trigger.channel): return bot.reply("There is already a game running in this channel.") @@ -59,8 +59,8 @@ def hangman(bot, trigger): + "Use '.hangman --start' to start one" return bot.reply(msg) - if len(trigger.group(2)) > 1: - if trigger.group(2) == bot.memory["hangman"][trigger.channel].word: + if len(trigger.args[1]) > 1: + if trigger.args[1] == bot.memory["hangman"][trigger.channel].word: bot.msg(f"{trigger.nick} has won!") bot.msg(bot.memory["hangman"][trigger.channel].word) bot.memory["hangman"].pop(trigger.channel) @@ -71,10 +71,10 @@ def hangman(bot, trigger): + f"{bot.memory['hangman'][trigger.channel].tries} tries left." bot.reply(msg) - elif len(trigger.group(2)) == 1: - if trigger.group(2) in bot.memory["hangman"][trigger.channel].word: + elif len(trigger.args[1]) == 1: + if trigger.args[1] in bot.memory["hangman"][trigger.channel].word: bot.reply("Correct!") - bot.memory["hangman"][trigger.channel].update(trigger.group(2)) + bot.memory["hangman"][trigger.channel].update(trigger.args[1]) else: bot.memory["hangman"][trigger.channel].tries -= 1 diff --git a/modules/help.py b/modules/help.py index de2afaf..6ea07f6 100755 --- a/modules/help.py +++ b/modules/help.py @@ -22,8 +22,8 @@ def clean_docstring(doc): @example('.help tell') def help(bot, trigger): """Shows a command's documentation, and possibly an example.""" - if trigger.group(2): - command = trigger.group(2) + if len(trigger.args) >= 2: + command = trigger.args[1] command = command.lower() if command not in bot.commands: return bot.msg("Command not found.") diff --git a/modules/isup.py b/modules/isup.py index bcd84a9..9efe6d6 100755 --- a/modules/isup.py +++ b/modules/isup.py @@ -10,10 +10,10 @@ from module import commands, require_chanmsg @commands('isup') def isup(bot, trigger): """Queries the given url to check if it's up or not.""" - url = trigger.group(2) - - if not url: + if len(trigger.args) < 2: return bot.reply("What URL do you want to check?") + url = trigger.args[1] + if url.startswith("192") and not trigger.owner: return bot.reply("Do not violate the LAN.") diff --git a/modules/lmgtfy.py b/modules/lmgtfy.py index aefa9c2..e341da8 100755 --- a/modules/lmgtfy.py +++ b/modules/lmgtfy.py @@ -7,6 +7,6 @@ from module import commands @commands('lmgtfy') def googleit(bot, trigger): """Let me just... google that for you.""" - if not trigger.group(2): + if len(trigger.args) < 2: return bot.msg('http://google.com/') - bot.msg('http://lmgtfy.com/?q=' + trigger.group(2).replace(' ', '+')) + bot.msg('http://lmgtfy.com/?q=' + trigger.args[1].replace(' ', '+')) diff --git a/modules/minecraft.py b/modules/minecraft.py index f71b38a..ab3a72e 100755 --- a/modules/minecraft.py +++ b/modules/minecraft.py @@ -16,7 +16,7 @@ def minecraft_start_server(bot, trigger): cmd = ["tmux", "send", "-t", "main:2", "./start.sh", "ENTER"] cmd_re = ["tmux", "send", "-t", "main:2", "^C", "ENTER"] msg = "Start signal sent to the minecraft server." - if trigger.group(2) == "-r": + if len(trigger.args) >= 2: msg = "Re-" + msg subprocess.run(cmd_re, check=True) subprocess.run(cmd, check=True) diff --git a/modules/movie.py b/modules/movie.py index 143cb6d..787afe4 100755 --- a/modules/movie.py +++ b/modules/movie.py @@ -46,10 +46,9 @@ def movieInfo(bot, trigger): Returns some information about a movie, like Title, Year, Rating, Genre and IMDB Link. """ - word = trigger.group(2) - if not word: + if len(trigger.args) < 2: return bot.reply("What movie?") - word = word.replace(" ", "+") + word = '+'.join(trigger.args[1:]) api_key = config.tmdb_api_key uri = "https://api.themoviedb.org/3/search/movie?" + \ @@ -151,8 +150,8 @@ def pickMovie(bot, trigger): else: bot.reply(movie[0]) - if trigger.group(2) == "-m": - trigger.set_group(f".movie {movie}") + if len(trigger.args) >= 2: + trigger.args = f".movie {movie}".strip().split(' ') movieInfo(bot, trigger) @@ -163,8 +162,10 @@ def addMovie(bot, trigger): """ Adds the specified movie to the movie database. """ + if len(trigger.args) < 2: + return bot.reply("What movie?") + movie = ' '.join(trigger.args[1:]) bot.memory['movie_lock'].acquire() - movie = trigger.group(2) try: bot.db.execute("INSERT INTO movie (movie_title, added_by) VALUES(?,?)", (movie, trigger.nick)) diff --git a/modules/privilege.py b/modules/privilege.py index dbeb9a6..76d9233 100644 --- a/modules/privilege.py +++ b/modules/privilege.py @@ -12,8 +12,8 @@ def check_privilege(bot, trigger): """ Checks the user's privilege. """ - if trigger.group(2): - nick = trigger.group(2) + if len(trigger.args) < 2: + nick = trigger.args[1] else: nick = trigger.nick diff --git a/modules/rand.py b/modules/rand.py index 15ae926..675ea53 100755 --- a/modules/rand.py +++ b/modules/rand.py @@ -16,19 +16,12 @@ from module import commands, example @example(".rand 10 99", "random(10, 99) = 29") def rand(bot, trigger): """Replies with a random number between first and second argument.""" - arg1 = trigger.group(3) - arg2 = trigger.group(4) + arg1 = trigger.args[1] if len(trigger.args) >= 2 else 0 + arg2 = trigger.args[2] if len(trigger.args) >= 3 else sys.maxsize try: - if arg2 is not None: - low = int(arg1) - high = int(arg2) - elif arg1 is not None: - low = 0 - high = int(arg1) - else: - low = 0 - high = sys.maxsize + low = int(arg1) + high = int(arg2) except (ValueError, TypeError): return bot.reply("Arguments must be of integer type") @@ -48,8 +41,14 @@ def rand_letters(bot, trigger): Generates a series of string of random letters. """ - num_letters = int(trigger.group(3)) if trigger.group(3) else 8 - num_vowels = int(trigger.group(4)) if trigger.group(4) else 2 + arg1 = trigger.args[1] if len(trigger.args) >= 2 else 8 + arg2 = trigger.args[2] if len(trigger.args) >= 3 else 2 + + try: + num_letters = int(arg1) + num_vowels = int(arg2) + except (ValueError, TypeError): + return bot.reply("Arguments must be of integer type") msg = [] for _ in range(num_letters): diff --git a/modules/reload.py b/modules/reload.py index 7cc62d8..26fe487 100755 --- a/modules/reload.py +++ b/modules/reload.py @@ -13,9 +13,11 @@ import module @module.thread(False) def f_reload(bot, trigger): """Reloads a module, for use by admins only.""" - name = trigger.group(2) + if len(trigger.args) < 2: + return boy.reply("Reload what?") + name = trigger.args[1] - if not name or name == "*" or name.upper() == "ALL THE THINGS": + if name == "*" or name.upper() == "ALL THE THINGS": bot.load_modules() return bot.msg("done") @@ -35,9 +37,9 @@ def f_reload(bot, trigger): @module.thread(False) def f_load(bot, trigger): """Loads a module, for use by admins only.""" - name = trigger.group(2) - if not name: + if len(trigger.args) < 2: return bot.msg('Load what?') + name = trigger.args[1] if name in sys.modules: return bot.msg('Module already loaded, use reload.') @@ -61,9 +63,9 @@ def f_load(bot, trigger): @module.thread(False) def f_unload(bot, trigger): """Unloads a module, for use by admins only.""" - name = trigger.group(2) - if not name: + if len(trigger.args) < 2: return bot.msg('Unload what?') + name = trigger.args[1] if name not in sys.modules: name = "modules." + name diff --git a/modules/remind.py b/modules/remind.py index cb90394..28fc440 100755 --- a/modules/remind.py +++ b/modules/remind.py @@ -6,9 +6,8 @@ import os import re import time import sqlite3 -import datetime import threading -import collections +from datetime import datetime import config from module import commands, example @@ -133,15 +132,15 @@ multiplier = [ @example('.remind 3h45m Go to class') def remind(bot, trigger): """Gives you a reminder in the given amount of time.""" - if not trigger.group(2): + if len(trigger.args) == 1: return bot.msg("Missing arguments for reminder command.") - if trigger.group(3) and not trigger.group(4): + if len(trigger.args) == 2: reminder = '' else: - reminder = ' '.join(trigger.group[4:]) + reminder = ' '.join(trigger.args[2:]) duration = 0 - for n, group in enumerate(re.search(regex, trigger.group(3)).groups()): + for n, group in enumerate(re.search(regex, trigger.args[1]).groups()): if not group: continue duration += int(group) * multiplier[n] @@ -154,48 +153,24 @@ def remind(bot, trigger): @example('.at 14:45:45 Remove dick from oven') def at(bot, trigger): """ - Gives you a reminder at the given time. Takes hh:mm:ssUTC+/-## - message. Timezone, if provided, must be in UTC format. 24 hour - clock format only. + Gives you a reminder at the given time and date. Datetime must be in + YYYY-MM-DD HH:MM:SS format. Only the bot's timezone is used. """ - if not trigger.group(2): - return bot.msg("No arguments given for reminder command.") - if trigger.group(3) and not trigger.group(4): - return bot.msg("No message given for reminder.") - - regex = re.compile(r"(\d+):(\d+)(?::(\d+))?(?:UTC([+-]\d+))? (.*)") - match = regex.match(trigger.group(2)) - if not match: - return bot.reply("Sorry, but I didn't understand your input.") - - hour, minute, second, tz, message = match.groups() - if not second: - second = '0' - - if tz: - try: - tz = int(tz.replace("UTC", "")) - except ValueError: - bot.msg("Invalid timezone. Using the bot's current timezone.") - tz = None - - if tz: - timezone = datetime.timezone(datetime.timedelta(hours=tz)) + if len(trigger.args) == 1: + return bot.msg("Missing arguments for reminder command.") + if len(trigger.args) == 2: + reminder = '' else: - timezone = datetime.datetime.now().astimezone().tzinfo - # current timezone the bot is in + reminder = ' '.join(trigger.args[2:]) - now = datetime.datetime.now(timezone) - at_time = datetime.datetime(now.year, now.month, now.day, - int(hour), int(minute), int(second), - tzinfo=timezone) - timediff = at_time - now + try: + at_time = datetime.strptime(trigger.args[1], '%Y-%m-%d %H:%M:%S') + except ValueError: + return bot.msg("Datetime improperly formatted.") + diff = at_time - datetime.now() + duration = diff.seconds - duration = timediff.seconds - - if duration < 0: - duration += 86400 - create_reminder(bot, trigger, duration, message) + create_reminder(bot, trigger, duration, reminder) def create_reminder(bot, trigger, duration, message): @@ -213,9 +188,9 @@ def create_reminder(bot, trigger, duration, message): insert_reminder(bot, t, reminder) if duration >= 60: - remind_at = datetime.datetime.fromtimestamp(t) + remind_at = datetime.fromtimestamp(t) t_format = config.default_time_format - timef = datetime.datetime.strftime(remind_at, t_format) + timef = datetime.strftime(remind_at, t_format) bot.reply('Okay, will remind at %s' % timef) else: diff --git a/modules/resistor.py b/modules/resistor.py index 07f353e..5ec2ccb 100755 --- a/modules/resistor.py +++ b/modules/resistor.py @@ -60,13 +60,13 @@ def resist(bot, trigger): """ Displays the color band code of a resistor for the given resistance. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.msg("Please specify a value") parser = argparse.ArgumentParser() parser.add_argument("value", nargs="+") parser.add_argument("-r", "--reverse", action="store_true") parser.add_argument("-n", "--num_bands", type=int, choices=[3,4,5,6], default=4) - args = parser.parse_args(trigger.group(2).split()) + args = parser.parse_args(trigger.args[1:]) if args.reverse: # bands-to-value bot.msg(bands_to_value(" ".join(args.value))) diff --git a/modules/rundown.py b/modules/rundown.py index 5e4c9ba..943f475 100755 --- a/modules/rundown.py +++ b/modules/rundown.py @@ -13,9 +13,10 @@ def rundown(bot, trigger): """ Provides rundown on demand. -c, --cabal for the IRCabal version. """ - if trigger.group(2) in ["-c", "--cabal"]: - with open(os.path.join(bot.static, "cabaldown.txt"), "r") as file: - data = file.read() + if len(trigger.args) > 2: + if trigger.args[1] in ["-c", "--cabal"]: + with open(os.path.join(bot.static, "cabaldown.txt"), "r") as file: + data = file.read() else: with open(os.path.join(bot.static, "rundown.txt"), "r") as file: data = file.read() diff --git a/modules/scramble.py b/modules/scramble.py index a45f64f..e02c575 100755 --- a/modules/scramble.py +++ b/modules/scramble.py @@ -54,10 +54,10 @@ def scramble(bot, trigger): Plays scramble. --start [-s] to start a new game, otherwise arguments are taken as attempts to solve. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Scramble what?") - if trigger.group(3) == "--start" or trigger.group(3) == "-s": + if trigger.args[1] == "--start" or trigger.args[1] == "-s": if bot.memory["scramble"].get(trigger.channel): return bot.reply("There is already a game running in this channel.") @@ -74,7 +74,7 @@ def scramble(bot, trigger): return bot.reply(msg) word = bot.memory["scramble"][trigger.channel].word - if isAnagram(bot, word, trigger.group(2)): + if isAnagram(bot, word, trigger.args[1]): bot.msg(f"{trigger.nick} has won!") msg = "Original word: " \ + bot.memory["scramble"][trigger.channel].word diff --git a/modules/sed.py b/modules/sed.py index 7e7ed6a..26704aa 100755 --- a/modules/sed.py +++ b/modules/sed.py @@ -8,135 +8,96 @@ using the sed notation (s///) commonly found in vi/vim. import re from module import hook -from tools import FulviaMemory def setup(bot): - bot.memory['find_lines'] = FulviaMemory() + bot.memory['sed_lines'] = {} @hook(True) def collectlines(bot, trigger): """Create a temporary log of what people say""" - - # Don't log things in PM if trigger.is_privmsg: return - # Add a log for the channel and nick, if there isn't already one - if trigger.channel not in bot.memory['find_lines']: - bot.memory['find_lines'][trigger.channel] = FulviaMemory() - if trigger.nick not in bot.memory['find_lines'][trigger.channel]: - bot.memory['find_lines'][trigger.channel][trigger.nick] = list() + if trigger.channel not in bot.memory['sed_lines']: + bot.memory['sed_lines'][trigger.channel] = {} + if trigger.nick not in bot.memory['sed_lines'][trigger.channel]: + bot.memory['sed_lines'][trigger.channel][trigger.nick] = [] - # Create a temporary list of the user's lines in a channel - templist = bot.memory['find_lines'][trigger.channel][trigger.nick] - line = trigger.group() + templist = bot.memory['sed_lines'][trigger.channel][trigger.nick] + line = ' '.join(trigger.args) if line.startswith("s/"): # Don't remember substitutions return - elif line.startswith("\x01ACTION"): # For /me messages - line = line[:-1] - templist.append(line) - else: - templist.append(line) + templist.append(line) del templist[:-10] # Keep the log to 10 lines per person - bot.memory['find_lines'][trigger.channel][trigger.nick] = templist + bot.memory['sed_lines'][trigger.channel][trigger.nick] = templist -#Match nick, s/find/replace/flags. Flags and nick are optional, nick can be -#followed by comma or colon, anything after the first space after the third -#slash is ignored, you can escape slashes with backslashes, and if you want to -#search for an actual backslash followed by an actual slash, you're shit out of -#luck because this is the fucking regex of death as it is. -# @rule(r"""(?: -# (\S+) # Catch a nick in group 1 -# [:,]\s+)? # Followed by colon/comma and whitespace, if given -# s/ # The literal s/ -# ( # Group 2 is the thing to find -# (?:\\/ | [^/])+ # One or more non-slashes or escaped slashes -# )/( # Group 3 is what to replace with -# (?:\\/ | [^/])* # One or more non-slashes or escaped slashes -# ) -# (?:/(\S+))? # Optional slash, followed by group 4 (flags) -# """) @hook(True) def findandreplace(bot, trigger): - # Don't bother in PM if trigger.is_privmsg: return - - rule = re.compile(r"(\S+)?(?:[:,]\s|^)s\/((?:\\\/|[^/])+)\/((?:\\\/|[^/])*"\ - + r")(?:\/(\S+))?") - group = rule.search(trigger.group(0)) - if not group: + if not trigger.args[0].startswith('s') and trigger.args[0][-1] not in ':,': return - g = (trigger.group(0),) + group.groups() - trigger.set_group(g) - - # Correcting other person vs self. - rnick = (trigger.group(1) or trigger.nick) - - search_dict = bot.memory['find_lines'] - # only do something if there is conversation to work with - if trigger.channel not in search_dict: - return - if rnick not in search_dict[trigger.channel]: + line = ' '.join(trigger.args) + if 's/' not in line: return - #TODO rest[0] is find, rest[1] is replace. These should be made variables of - #their own at some point. - rest = [trigger.group(2), trigger.group(3)] - rest[0] = rest[0].replace(r'\/', '/') - rest[1] = rest[1].replace(r'\/', '/') - me = False # /me command - flags = (trigger.group(4) or '') - print(flags) + items = [] + line = line[line.index('s/')+2:] + i = 0 + while True: + i = line.find('/', i) + if i == -1: + break + if line[max(i-1, 0)] == '\\' and line[max(i-2, 0)] != '\\': + i += 1 + pass + else: + items.append(line[:i]) + line = line[i+1:] + i = 0 + items.append(line) + + if len(items) < 2: + return + find, replace = items[:2] + find = find.replace(r'\/', '/') + flags = items[2] if len(items) >= 3 else '' - # If g flag is given, replace all. Otherwise, replace once. if 'g' in flags: count = 0 else: count = 1 - # repl is a lambda function which performs the substitution. i flag turns - # off case sensitivity. re.U turns on unicode replacement. - if 'i' in flags: - regex = re.compile(re.escape(rest[0]), re.U | re.I) - repl = lambda s: re.sub(regex, rest[1], s, count == 1) - else: - repl = lambda s: re.sub(rest[0], rest[1], s, count) - - # Look back through the user's lines in the channel until you find a line - # where the replacement works - new_phrase = None - for line in reversed(search_dict[trigger.channel][rnick]): - if line.startswith("\x01ACTION"): - me = True # /me command - line = line[8:] + try: + if 'i' in flags: + regex = re.compile(find, re.I) else: - me = False - new_phrase = repl(line) - if new_phrase != line: # we are done - break + regex = re.compile(find) + except re.error: + return - if not new_phrase or new_phrase == line: - return # Didn't find anything - - # Save the new "edited" message. - action = (me and '\x01ACTION ') or '' # If /me message, prepend \x01ACTION - templist = search_dict[trigger.channel][rnick] - templist.append(action + new_phrase) - search_dict[trigger.channel][rnick] = templist - bot.memory['find_lines'] = search_dict - - # output - if not me: - new_phrase = f"\x02meant\x0f to say: {new_phrase}" - if trigger.group(1): - phrase = f"{trigger.nick} thinks {rnick} {new_phrase}" + if not trigger.args[0].startswith('s'): + nick = trigger.args[0][:-1] + if nick not in bot.memory['sed_lines'][trigger.channel]: + return else: - phrase = f"{trigger.nick} {new_phrase}" + nick = trigger.nick - bot.msg(phrase) + for line in reversed(bot.memory['sed_lines'][trigger.channel][nick]): + new_line = re.sub(regex, replace, line, count) + if new_line != line: + break + else: + return + + if trigger.args[0].startswith('s'): + msg = f"{trigger.nick} \x02meant\x0f to say: {new_line}" + else: + msg = f"{trigger.nick} thinks {nick} \x02meant\x0f to say: {new_line}" + + bot.msg(msg) diff --git a/modules/seen.py b/modules/seen.py index 2b61612..fc6cc5f 100755 --- a/modules/seen.py +++ b/modules/seen.py @@ -65,7 +65,7 @@ def seen(bot, trigger): -m, --message - includes the first/last message the user sent. -c, --context - includes irc logs before and after their last message as context. Implies --message. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Seen who?") parser = argparse.ArgumentParser() @@ -74,7 +74,7 @@ def seen(bot, trigger): parser.add_argument("-f", "--first", action="store_true") parser.add_argument("-m", "--message", action="store_true") parser.add_argument("-c", "--context", action="store_true") - args = parser.parse_args(trigger.group[3:]) + args = parser.parse_args(trigger.args[1:]) if args.nick == bot.nick: return bot.reply("I'm right here!") @@ -142,9 +142,9 @@ def dump_seen_db(bot): @require_chanmsg def seen_hook(bot, trigger): bot.memory["seen_lock"].acquire() - last = (time.time(), trigger.channel, trigger.group(0)) + last = (time.time(), trigger.channel, ' '.join(trigger.args)) if not trigger.nick in bot.memory["seen"]: - first = (time.time(), trigger.channel, trigger.group(0)) + first = (time.time(), trigger.channel, ' '.join(trigger.args)) else: first = bot.memory["seen"][trigger.nick][:3] seen = first + last diff --git a/modules/slur.py b/modules/slur.py index 6430d2e..2cb2892 100644 --- a/modules/slur.py +++ b/modules/slur.py @@ -37,7 +37,7 @@ def slur(bot, trigger): parser.add_argument("-r", "--race", type=str, nargs='+') parser.add_argument("-s", "--slur", type=str) parser.add_argument("-l", "--list", action="store_true") - args = parser.parse_args(trigger.group[3:]) + args = parser.parse_args(trigger.args[1:]) if args.list: races = bot.db.execute("SELECT DISTINCT race FROM slur").fetchall() diff --git a/modules/spellcheck.py b/modules/spellcheck.py index d68d112..0a243ec 100755 --- a/modules/spellcheck.py +++ b/modules/spellcheck.py @@ -13,9 +13,9 @@ def spellcheck(bot, trigger): Says whether the given word is spelled correctly, and gives suggestions if it's not. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("What word?") - word = trigger.group(2) + word = trigger.args[1] if " " in word: return bot.msg("One word at a time, please") dictionary = enchant.Dict("en_US") diff --git a/modules/tell.py b/modules/tell.py index b2f26c4..201d7cc 100755 --- a/modules/tell.py +++ b/modules/tell.py @@ -67,12 +67,14 @@ def setup(bot): @example('.tell iou1name you broke something again.') def tell(bot, trigger): """Give someone a message the next time they're seen""" - if not trigger.group(3): + if len(trigger.args) < 2: return bot.reply("Tell whom?") + if len(trigger.args) < 3: + return bot.reply("Tell them what?") teller = trigger.nick - tellee = trigger.group(3).rstrip('.,:;') - message = trigger.group(2).replace(tellee, "", 1).strip() + tellee = trigger.args[1].rstrip('.,:;') + message = ' '.join(trigger.args[2:]) if not message: return bot.reply(f"Tell {tellee} what?") diff --git a/modules/tld.py b/modules/tld.py index 2cd1b99..2228b52 100755 --- a/modules/tld.py +++ b/modules/tld.py @@ -13,11 +13,9 @@ URI = 'https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains' @example('.tld me') def gettld(bot, trigger): """Show information about the given Top Level Domain.""" - word = trigger.group(2).strip() - if not word: + if len(trigger.args) < 2: return bot.reply("What TLD?") - if " " in word: - return bot.reply("One TLD at a time.") + word = trigger.args[1] if not word.startswith("."): word = "." + word diff --git a/modules/topic.py b/modules/topic.py index f3bfcba..00f4b45 100755 --- a/modules/topic.py +++ b/modules/topic.py @@ -48,9 +48,9 @@ def addTopic(bot, trigger): """ Adds the specified topic to the topic database. """ - topic = trigger.group(2) - if not topic: + if len(trigger.args) < 2: return bot.msg("Please be providing a topic sir.") + topic = trigger.args[1] bot.memory['topic_lock'].acquire() try: bot.db.execute("INSERT INTO topic (topic, added_by) VALUES(?,?)", diff --git a/modules/translate.py b/modules/translate.py index fe66dbc..97291d6 100755 --- a/modules/translate.py +++ b/modules/translate.py @@ -42,14 +42,14 @@ def tr2(bot, trigger): -i LANG, --inlang LANG - specifies the assumed input language. -o LANG, --outlang LANG - specifies the desired output language. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Translate what?") parser = argparse.ArgumentParser() parser.add_argument("text", nargs=argparse.REMAINDER) parser.add_argument("-i", "--inlang", default="auto") parser.add_argument("-o", "--outlang", default="en") - args = parser.parse_args(trigger.group(2).split()) + args = parser.parse_args(trigger.args[1:]) args.text = " ".join(args.text) tr_text, in_lang = translate(args.text, in_lang=args.inlang, @@ -60,9 +60,9 @@ def tr2(bot, trigger): @commands('mangle') def mangle(bot, trigger): """Repeatedly translate the input until it makes absolutely no sense.""" - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Mangle what?") - tr_text = trigger.group(2) + tr_text = ' '.join(trigger.args[1:]) long_lang_list = ['fr', 'de', 'es', 'it', 'no', 'he', 'la', 'ja', 'cy', 'ar', 'yi', 'zh', 'nl', 'ru', 'fi', 'hi', 'af', 'jw', 'mr', 'ceb', diff --git a/modules/unicode_info.py b/modules/unicode_info.py index 883dc0d..672c716 100755 --- a/modules/unicode_info.py +++ b/modules/unicode_info.py @@ -11,9 +11,9 @@ from module import commands, example @example('.u 203D', 'U+203D INTERROBANG (‽)') def codepoint(bot, trigger): """Looks up unicode information.""" - arg = trigger.group(2) - if not arg: + if len(trigger.args) < 2: return bot.reply('What code point do you want me to look up?') + arg = ' '.join(trigger.args[1]) stripped = arg.strip() if len(stripped) > 0: arg = stripped diff --git a/modules/units.py b/modules/units.py index ea536a7..cfebf9b 100755 --- a/modules/units.py +++ b/modules/units.py @@ -43,7 +43,7 @@ def temperature(bot, trigger): Convert temperatures """ try: - source = find_temp.match(trigger.group(2)).groups() + source = find_temp.match(' '.join(trigger.args[1:])).groups() except (AttributeError, TypeError): return bot.reply("That's not a valid temperature.") unit = source[1].upper() @@ -77,7 +77,7 @@ def distance(bot, trigger): Convert distances """ try: - source = find_length.match(trigger.group(2)).groups() + source = find_length.match(' '.join(trigger.args[1:])).groups() except (AttributeError, TypeError): return bot.reply("That's not a valid length unit.") unit = source[1].lower() @@ -151,7 +151,7 @@ def mass(bot, trigger): Convert mass """ try: - source = find_mass.match(trigger.group(2)).groups() + source = find_mass.match(' '.join(trigger.args[1:])).groups() except (AttributeError, TypeError): return bot.reply("That's not a valid mass unit.") unit = source[1].lower() diff --git a/modules/uptime.py b/modules/uptime.py index 780c7e3..5261639 100755 --- a/modules/uptime.py +++ b/modules/uptime.py @@ -27,12 +27,12 @@ def uptime(bot, trigger): @commands('updick') def updick(bot, trigger): """.updick - Returns the uptime of Fulvia, measured in dicks.""" - if trigger.group(2): - if trigger.group(2) in bot.users: + if len(trigger.args) < 2: + if trigger.args[1] in bot.users: d = defer.Deferred() d.addCallback(idleTime, bot) - bot.memory["idle_callbacks"][trigger.group(2)] = d - bot.whois(trigger.group(2)) + bot.memory["idle_callbacks"][trigger.args[1]] = d + bot.whois(trigger.args[1]) else: delta = datetime.datetime.now() - bot.memory["uptime"] bot.msg("8" + "="*delta.days + "D") @@ -41,12 +41,12 @@ def updick(bot, trigger): @commands('upwulf') def upwulf(bot, trigger): """.upwulf - Returns the uptime of Fulvia, measured in Adalwulfs.""" - if trigger.group(2): - if trigger.group(2) in bot.users: + if len(trigger.args) < 2: + if trigger.args[1] in bot.users: d = defer.Deferred() - d.addCallback(idleTimeWulf, bot) - bot.memory["idle_callbacks"][trigger.group(2)] = d - bot.whois(trigger.group(2)) + d.addCallback(idleTime, bot) + bot.memory["idle_callbacks"][trigger.args[1]] = d + bot.whois(trigger.args[1]) else: delta = datetime.datetime.now() - bot.memory["uptime"] bot.msg("Adalwulf" + "_"*delta.days) @@ -75,7 +75,9 @@ def idleTimeWulf(result, bot): @commands('unix') def unixtolocal(bot, trigger): """Converts the given timestamp from unix time to local time.""" - unix = int(trigger.group(2)) + if len(trigger.args) < 2: + return bot.reply("Unix what?") + unix = int(trigger.args[1]) dt = datetime.datetime.utcfromtimestamp(unix) dt = dt.replace(tzinfo=datetime.timezone.utc) bot.msg(dt.astimezone(tz=None).strftime('%Y-%m-%d %H:%M:%S')) diff --git a/modules/url.py b/modules/url.py index 6a7b429..6da098b 100755 --- a/modules/url.py +++ b/modules/url.py @@ -36,11 +36,11 @@ def title_auto(bot, trigger): Automatically show titles for URLs. For shortened URLs/redirects, find where the URL redirects to and show the title for that. """ - if "http" not in trigger.group(0): + if "http" not in ' '.join(trigger.args): return url_finder = re.compile(r"((?:http|https)(?::\/\/\S+))", re.IGNORECASE) - urls = re.findall(url_finder, trigger.group(0)) + urls = re.findall(url_finder, ' '.join(trigger.args)) if len(urls) == 0: return diff --git a/modules/watcher.py b/modules/watcher.py index 025f9ca..1f266e9 100755 --- a/modules/watcher.py +++ b/modules/watcher.py @@ -85,10 +85,10 @@ def watch(bot, trigger): """ A thread watcher for 4chan. """ - url = trigger.group(3) - name = trigger.group(4) - if not name: - name = "Anonymous" + if len(trigger.args) < 2: + boy.reply("What thread?") + url = trigger.args[1] + name = trigger.args[2] if len(trigger.args) >= 3 else "Anonymous" if url in bot.memory["watcher"].keys(): return bot.msg("Error: I'm already watching that thread.") @@ -120,7 +120,9 @@ def unwatch(bot, trigger): """ Stops the thread watcher thread for that thread. """ - url = trigger.group(2) + if len(trigger.args) < 2: + boy.reply("What thread?") + url = trigger.args[1] try: bot.memory["watcher"][url].stop.set() bot.memory["watcher"].pop(url) diff --git a/modules/weather.py b/modules/weather.py index f823ec2..520feb3 100755 --- a/modules/weather.py +++ b/modules/weather.py @@ -17,11 +17,13 @@ def weather(bot, trigger): -m, --metric - uses metric units instead of imperial. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("Weather where?") - location = trigger.group(3) + location = trigger.args[1] if location == '-m' or location == '--metric': - location = trigger.group(4) + if len(trigger.args) < 3: + return bot.reply("Weather where?") + location = trigger.args[2] units = 'metric' else: units = 'imperial' diff --git a/modules/wikipedia.py b/modules/wikipedia.py index dc646b4..72bcdb9 100755 --- a/modules/wikipedia.py +++ b/modules/wikipedia.py @@ -74,10 +74,10 @@ def wiki_info(bot, url): @example('.wiki San Francisco') def wikipedia(bot, trigger): """Search wikipedia and return a snippet of the results.""" - if trigger.group(2) is None: + if len(trigger.args) < 2: return bot.reply("What do you want me to look up?") - query = trigger.group(2) + query = ' '.join(trigger.args[1:]) if not query: return bot.reply("What do you want me to look up?") diff --git a/modules/wiktionary.py b/modules/wiktionary.py index 23b6182..c880c35 100755 --- a/modules/wiktionary.py +++ b/modules/wiktionary.py @@ -76,9 +76,9 @@ def format(result, definitions, number=2): @example('.dict bailiwick') def wiktionary(bot, trigger): """Look up a word on Wiktionary.""" - word = trigger.group(2) - if word is None: + if len(trigger.args) < 2: return bot.reply('You must tell me what to look up!') + word = trigger.args[1] _, definitions = wikt(word) if not definitions: diff --git a/modules/willilike.py b/modules/willilike.py index 9a5966f..7b8e006 100755 --- a/modules/willilike.py +++ b/modules/willilike.py @@ -8,7 +8,7 @@ from module import commands, example @example('.willilike Banished Quest') def willilike(bot, trigger): """An advanced AI that will determine if you like something.""" - if trigger.group(2): + if len(trigger.args) >= 2: bot.reply("No.") @commands('upvote') diff --git a/modules/wolfram.py b/modules/wolfram.py index 7ff1a8e..6987077 100755 --- a/modules/wolfram.py +++ b/modules/wolfram.py @@ -15,11 +15,11 @@ def wa_command(bot, trigger): """ Queries WolframAlpha. """ - if not trigger.group(2): + if len(trigger.args) < 2: return bot.reply("You must provide a query.") if not config.wolfram_app_id: bot.reply("Wolfram|Alpha API app ID not configured.") - query = trigger.group(2).strip() + query = ' '.join(trigger.args[1:]) app_id = config.wolfram_app_id units = config.wolfram_units diff --git a/modules/xkcd.py b/modules/xkcd.py index d2387b5..4517f8c 100755 --- a/modules/xkcd.py +++ b/modules/xkcd.py @@ -54,9 +54,9 @@ def xkcd(bot, trigger): """ latest = get_info() max_int = latest['num'] - if trigger.group(2): + if len(trigger.args) >= 2: try: - num = int(trigger.group(2)) + num = int(trigger.args[1]) except ValueError: return bot.reply("Invalid input.") num = validate_num(num, max_int) diff --git a/trigger.py b/trigger.py index 744b099..0b6d6de 100755 --- a/trigger.py +++ b/trigger.py @@ -2,8 +2,6 @@ """ The trigger abstraction layer. """ -import datetime - import config def split_user(user): @@ -18,75 +16,14 @@ def split_user(user): return nick, ident, host -class Group(list): - """ - Custom list class that permits calling it like a function so as to - emulate a re.group instance. - """ - def __init__(self, message): - """ - Initializes the group class. If 'message' is a string, we split - it into groups according to the usual trigger.group structure. - Otherwise we assume it's already been split appropriately. - """ - if type(message) == str: - message = self.split_group(message) - list.__init__(self, message) - - - def __call__(self, n=0): - """ - Allows you to call the instance like a function. Or a re.group - instance ;^). - If calling would result in an index error, None is returned instead. - """ - try: - item = list.__getitem__(self, n) - except IndexError: - item = None - return item - - - def split_group(self, message): - """ - Splits the message by spaces. - group(0) is always the entire message. - group(1) is always the first word of the message minus the prefix, if - present. This is usually just the command. - group(2) is always the entire message after the first word. - group(3+) is always every individual word after the first word. - """ - group = [] - group.append(message) - words = message.split() - group.append(words[0].replace(config.prefix, "", 1)) - group.append(" ".join(words[1:])) - group += words[1:] - - return group - - class Trigger(): - def __init__(self, user, channel, message, event): + def __init__(self, user, channel, message): self.channel = channel """ The channel from which the message was sent. In a private message, this is the nick that sent the message. """ - self.time = datetime.datetime.now() - """ - A datetime object at which the message was received by the IRC server. - If the server does not support server-time, then `time` will be the time - that the message was received by Fulvia. - """ - - self.raw = "" - """ - The entire message, as sent from the server. This includes the CTCP - \\x01 bytes and command, if they were included. - """ - self.is_privmsg = not channel.startswith("#") """True if the trigger is from a user, False if it's from a channel.""" @@ -107,50 +44,15 @@ class Trigger(): self.host = host """The hostname of the person who sent the message""" - self.event = event - """ - The IRC event (e.g. ``PRIVMSG`` or ``MODE``) which triggered the - message. - """ - - self.group = Group(message) - """The ``group`` function of the ``match`` attribute. - - See Python :mod:`re` documentation for details.""" - - self.args = () - """ - A tuple containing each of the arguments to an event. These are the - strings passed between the event name and the colon. For example, - setting ``mode -m`` on the channel ``#example``, args would be - ``('#example', '-m')`` - """ + self.args = message.strip().split(' ') + """Pseudo-ARGV for a bot command.""" admins = config.admins + [config.owner] - self.admin = any([self.compare_hostmask(admin) for admin in admins]) + self.admin = any([user == admin for admin in admins]) """ - True if the nick which triggered the command is one of the bot's + True if the user which triggered the command is one of the bot's admins. """ - self.owner = self.compare_hostmask(config.owner) + self.owner = user == config.owner """True if the nick which triggered the command is the bot's owner.""" - - - def compare_hostmask(self, compare_against): - """ - Compares the current hostmask against the given one. If ident is not - None, it uses that, otherwise it only uses @. - """ - if self.ident: - return compare_against == self.hostmask - else: - return compare_against == "@".join(self.nick, self.host) - - - def set_group(self, line): - """ - Allows a you to easily change the current group to a new Group - instance. - """ - self.group = Group(line)