refactored trigger
This commit is contained in:
parent
7159deb7f8
commit
1b71e73757
22
bot.py
22
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()
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:]))
|
||||
|
|
|
@ -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.')
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -14,9 +14,9 @@ def generic_countdown(bot, trigger):
|
|||
"""
|
||||
.countdown <year> <month> <day> - 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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:]))
|
||||
|
|
|
@ -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])
|
||||
bot.msg(data[num])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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.")
|
||||
|
||||
|
|
|
@ -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(' ', '+'))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
153
modules/sed.py
153
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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?")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(?,?)",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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?")
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
110
trigger.py
110
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 <nick>@<host>.
|
||||
"""
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user