This commit is contained in:
dngfx 2018-08-31 10:50:37 +01:00
parent bc5e08ead3
commit abed9cf4ea
60 changed files with 1347 additions and 817 deletions

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("invite").hook( bot.events.on("received").on("invite").hook(

View file

@ -1,17 +1,22 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("changenickname" bot.events.on("received").on("command").on("changenickname"
).hook(self.change_nickname, permission="changenickname", ).hook(self.change_nickname,
min_args=1, help="Change my nickname", usage="<nickname>") permission="changenickname",
min_args=1,
help="Change my nickname",
usage="<nickname>")
bot.events.on("received").on("command").on("raw" bot.events.on("received").on("command").on("raw"
).hook(self.raw, permission="raw", min_args=1, ).hook(self.raw,
permission="raw",
min_args=1,
help="Send a raw IRC line through the bot", help="Send a raw IRC line through the bot",
usage="<raw line>") usage="<raw line>")
bot.events.on("received").on("command").on("part" bot.events.on("received").on("command").on("part"
).hook(self.part, permission="part", min_args=1, ).hook(self.part,
permission="part",
min_args=1,
help="Part from a channel", help="Part from a channel",
usage="<#channel>") usage="<#channel>")

View file

@ -1,5 +1,6 @@
import Utils import Utils
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot

View file

@ -1,7 +1,9 @@
import Utils import Utils
class Module(object): class Module(object):
_name = "BTC" _name = "BTC"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("btc").hook( bot.events.on("received").on("command").on("btc").hook(
@ -17,7 +19,8 @@ class Module(object):
conversion = page[currency] conversion = page[currency]
buy, sell = conversion["buy"], conversion["sell"] buy, sell = conversion["buy"], conversion["sell"]
event["stdout"].write("1 BTC = %.2f %s (buy) %.2f %s " event["stdout"].write("1 BTC = %.2f %s (buy) %.2f %s "
"(sell)" % (buy, currency, sell, currency)) "(sell)" % (
buy, currency, sell, currency))
else: else:
event["stderr"].write("Unknown currency, available " event["stderr"].write("Unknown currency, available "
"currencies: %s" % ", ".join(page.keys())) "currencies: %s" % ", ".join(page.keys()))

View file

@ -6,12 +6,15 @@ import Utils
URL_BITLYSHORTEN = "https://api-ssl.bitly.com/v3/shorten" URL_BITLYSHORTEN = "https://api-ssl.bitly.com/v3/shorten"
REGEX_URL = re.compile("https?://", re.I) REGEX_URL = re.compile("https?://", re.I)
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("get").on("shortlink").hook(self.shortlink) bot.events.on("get").on("shortlink").hook(self.shortlink)
bot.events.on("received").on("command").on("shorten" bot.events.on("received").on("command").on("shorten"
).hook(self.shorten, min_args=1, help="Shorten a URL.", ).hook(self.shorten,
min_args=1,
help="Shorten a URL.",
usage="<url>") usage="<url>")
def shortlink(self, event): def shortlink(self, event):

View file

@ -5,8 +5,10 @@ URL_GOOGLEBOOKS = "https://www.googleapis.com/books/v1/volumes"
URL_BOOKINFO = "https://books.google.co.uk/books?id=%s" URL_BOOKINFO = "https://books.google.co.uk/books?id=%s"
REGEX_BOOKID = re.compile("id=([\w\-]+)") REGEX_BOOKID = re.compile("id=([\w\-]+)")
class Module(object): class Module(object):
_name = "ISBN" _name = "ISBN"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("isbn").hook( bot.events.on("received").on("command").on("isbn").hook(

View file

@ -1,41 +1,67 @@
import Utils import Utils
class Module(object): class Module(object):
_name = "Channel Op" _name = "Channel Op"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("kick", "k" bot.events.on("received").on("command").on("kick", "k"
).hook(self.kick, channel_only=True, require_mode="o", ).hook(self.kick,
min_args=1, help="Kick a user from the channel", channel_only=True,
require_mode="o",
min_args=1,
help="Kick a user from the channel",
usage="<nickname> [reason]") usage="<nickname> [reason]")
bot.events.on("received").on("command").on("ban" bot.events.on("received").on("command").on("ban"
).hook(self.ban, channel_only=True, require_mode="o", ).hook(self.ban,
min_args=1, help="Ban a user/hostmask from the channel", channel_only=True,
require_mode="o",
min_args=1,
help="Ban a user/hostmask from the channel",
usage="<nickname/hostmask>") usage="<nickname/hostmask>")
bot.events.on("received").on("command").on("unban" bot.events.on("received").on("command").on("unban"
).hook(self.unban, channel_only=True, require_mode="o", ).hook(self.unban,
min_args=1, help="Unban a user/hostmask from the channel", channel_only=True,
require_mode="o",
min_args=1,
help="Unban a user/hostmask from the channel",
usage="<nickname/hostmask>") usage="<nickname/hostmask>")
bot.events.on("received").on("command").on("kickban", "kb" bot.events.on("received").on("command").on("kickban", "kb"
).hook(self.kickban, channel_only=True, require_mode="o", ).hook(self.kickban,
min_args=1, help="Kickban a user from the channel", channel_only=True,
require_mode="o",
min_args=1,
help="Kickban a user from the channel",
usage="<nickanme> [reason]") usage="<nickanme> [reason]")
bot.events.on("received").on("command").on("op" bot.events.on("received").on("command").on("op"
).hook(self.op, channel_only=True, require_mode="o", ).hook(self.op,
help="Give +o to a user", usage="[nickname]") channel_only=True,
require_mode="o",
help="Give +o to a user",
usage="[nickname]")
bot.events.on("received").on("command").on("deop" bot.events.on("received").on("command").on("deop"
).hook(self.deop, channel_only=True, require_mode="o", ).hook(self.deop,
help="Take +o from a user", usage="[nickname]") channel_only=True,
require_mode="o",
help="Take +o from a user",
usage="[nickname]")
bot.events.on("received").on("command").on("voice" bot.events.on("received").on("command").on("voice"
).hook(self.voice, channel_only=True, require_mode="o", ).hook(self.voice,
help="Give +v to a user", usage="[nickname]") channel_only=True,
require_mode="o",
help="Give +v to a user",
usage="[nickname]")
bot.events.on("received").on("command").on("devoice" bot.events.on("received").on("command").on("devoice"
).hook(self.devoice, channel_only=True, require_mode="o", ).hook(self.devoice,
help="Take +v from a user", usage="[nickname]") channel_only=True,
require_mode="o",
help="Take +v from a user",
usage="[nickname]")
bot.events.on("received").on("message").on("channel").hook( bot.events.on("received").on("message").on("channel").hook(
self.highlight_spam) self.highlight_spam)
@ -43,7 +69,8 @@ class Module(object):
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="highlight-spam-threshold", "channelset").assure_call(setting="highlight-spam-threshold",
help="Set the number of nicknames in a message that " help="Set the number of nicknames in a message that "
"qualifies as spam", validate=Utils.int_or_none) "qualifies as spam",
validate=Utils.int_or_none)
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="highlight-spam-protection", "channelset").assure_call(setting="highlight-spam-protection",
help="Enable/Disable highlight spam protection", help="Enable/Disable highlight spam protection",
@ -51,7 +78,8 @@ class Module(object):
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="highlight-spam-ban", "channelset").assure_call(setting="highlight-spam-ban",
help="Enable/Disable banning highlight spammers " help="Enable/Disable banning highlight spammers "
"instead of just kicking", validate=Utils.bool_or_none) "instead of just kicking",
validate=Utils.bool_or_none)
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="ban-format", "channelset").assure_call(setting="ban-format",
help="Set ban format ($n = nick, $u = username, $h = hostname)") help="Set ban format ($n = nick, $u = username, $h = hostname)")
@ -74,7 +102,9 @@ class Module(object):
def _ban_format(self, user, s): def _ban_format(self, user, s):
return s.replace("$n", user.nickname).replace("$u", user.username return s.replace("$n", user.nickname).replace("$u", user.username
).replace("$h", user.hostname) ).replace("$h",
user.hostname)
def _ban(self, channel, ban, user): def _ban(self, channel, ban, user):
format = channel.get_setting("ban-format", "*!$u@$h") format = channel.get_setting("ban-format", "*!$u@$h")
hostmask_split = format.split("$$") hostmask_split = format.split("$$")
@ -84,12 +114,14 @@ class Module(object):
channel.send_ban(hostmask) channel.send_ban(hostmask)
else: else:
channel.send_unban(hostmask) channel.send_unban(hostmask)
def ban(self, event): def ban(self, event):
target_user = event["server"].get_user(event["args_split"][0]) target_user = event["server"].get_user(event["args_split"][0])
if event["target"].has_user(target_user): if event["target"].has_user(target_user):
self._ban(event["target"], True, target_user) self._ban(event["target"], True, target_user)
else: else:
event["target"].send_ban(event["args_split"][0]) event["target"].send_ban(event["args_split"][0])
def unban(self, event): def unban(self, event):
target_user = event["server"].get_user(event["args_split"][0]) target_user = event["server"].get_user(event["args_split"][0])
if event["target"].has_user(target_user): if event["target"].has_user(target_user):
@ -108,14 +140,17 @@ class Module(object):
target = event["user"].nickname if not event["args_split"] else event[ target = event["user"].nickname if not event["args_split"] else event[
"args_split"][0] "args_split"][0]
event["target"].send_mode("+o", target) event["target"].send_mode("+o", target)
def deop(self, event): def deop(self, event):
target = event["user"].nickname if not event["args_split"] else event[ target = event["user"].nickname if not event["args_split"] else event[
"args_split"][0] "args_split"][0]
event["target"].send_mode("-o", target) event["target"].send_mode("-o", target)
def voice(self, event): def voice(self, event):
target = event["user"].nickname if not event["args_split"] else event[ target = event["user"].nickname if not event["args_split"] else event[
"args_split"][0] "args_split"][0]
event["target"].send_mode("+v", target) event["target"].send_mode("+v", target)
def devoice(self, event): def devoice(self, event):
target = event["user"].nickname if not event["args_split"] else event[ target = event["user"].nickname if not event["args_split"] else event[
"args_split"][0] "args_split"][0]
@ -124,7 +159,8 @@ class Module(object):
def highlight_spam(self, event): def highlight_spam(self, event):
if event["channel"].get_setting("highlight-spam-protection", False): if event["channel"].get_setting("highlight-spam-protection", False):
nicknames = list(map(lambda user: user.nickname, nicknames = list(map(lambda user: user.nickname,
event["channel"].users)) + [event["server"].nickname] event["channel"].users)) + [
event["server"].nickname]
highlights = set(nicknames) & set(event["message_split"]) highlights = set(nicknames) & set(event["message_split"])
if len(highlights) > 1 and len(highlights) >= event["channel" if len(highlights) > 1 and len(highlights) >= event["channel"

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received.numeric.001").hook( bot.events.on("received.numeric.001").hook(
@ -15,7 +13,8 @@ class Module(object):
keys_sorted = list(map(lambda x: x[1], keys_sorted = list(map(lambda x: x[1],
sorted(chan_keys.items(), sorted(chan_keys.items(),
key=lambda x: channels_sorted.index(x[0])))) key=lambda x: channels_sorted.index(
x[0]))))
for i in range(len(channels_sorted)): for i in range(len(channels_sorted)):
channel = channels_sorted[i] channel = channels_sorted[i]

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot

View file

@ -25,6 +25,7 @@ THIRD_COLUMN = list(range(1, 37))[2::3]
REGEX_STREET = re.compile("street([1-9]|1[0-2])$") REGEX_STREET = re.compile("street([1-9]|1[0-2])$")
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -40,8 +41,11 @@ class Module(object):
bot.events.on("received.command.redeemcoins").hook( bot.events.on("received.command.redeemcoins").hook(
self.redeem_coins, help="Redeem free coins") self.redeem_coins, help="Redeem free coins")
bot.events.on("received.command.flip").hook(self.flip, bot.events.on("received.command.flip").hook(self.flip,
help="Bet coins on a coin flip", usage= help="Bet coins on a coin flip",
"heads|tails <coin amount>", min_args=2, protect_registered=True) usage=
"heads|tails <coin amount>",
min_args=2,
protect_registered=True)
bot.events.on("received.command.sendcoins").hook( bot.events.on("received.command.sendcoins").hook(
self.send, min_args=2, help="Send coins to a user", self.send, min_args=2, help="Send coins to a user",
usage="<nickname> <amount>", authenticated=True) usage="<nickname> <amount>", authenticated=True)
@ -64,7 +68,8 @@ class Module(object):
target = event["user"] target = event["user"]
coins = decimal.Decimal(target.get_setting("coins", "0.0")) coins = decimal.Decimal(target.get_setting("coins", "0.0"))
event["stdout"].write("%s has %s coin%s" % (target.nickname, event["stdout"].write("%s has %s coin%s" % (target.nickname,
"{0:.2f}".format(coins), "" if coins == 1 else "s")) "{0:.2f}".format(coins),
"" if coins == 1 else "s"))
def reset_coins(self, event): def reset_coins(self, event):
target = event["server"].get_user(event["args_split"][0]) target = event["server"].get_user(event["args_split"][0])
@ -76,7 +81,6 @@ class Module(object):
target.del_setting("coins") target.del_setting("coins")
event["stdout"].write("Reset coins for %s" % target.nickname) event["stdout"].write("Reset coins for %s" % target.nickname)
def richest(self, event): def richest(self, event):
all_coins = event["server"].get_all_user_settings("coins", []) all_coins = event["server"].get_all_user_settings("coins", [])
all_coins = list(filter(lambda coin: decimal.Decimal(coin[1]), all_coins = list(filter(lambda coin: decimal.Decimal(coin[1]),
@ -87,7 +91,8 @@ class Module(object):
top_10 = sorted(all_coins.keys()) top_10 = sorted(all_coins.keys())
top_10 = sorted(top_10, key=all_coins.get, reverse=True)[:10] top_10 = sorted(top_10, key=all_coins.get, reverse=True)[:10]
top_10 = ", ".join("%s (%s)" % (Utils.prevent_highlight(event[ top_10 = ", ".join("%s (%s)" % (Utils.prevent_highlight(event[
"server"].get_user(nickname).nickname), "{0:.2f}".format( "server"].get_user(
nickname).nickname), "{0:.2f}".format(
all_coins[nickname])) for nickname in top_10) all_coins[nickname])) for nickname in top_10)
event["stdout"].write("Richest users: %s" % top_10) event["stdout"].write("Richest users: %s" % top_10)
@ -102,7 +107,8 @@ class Module(object):
if last_redeem == None or (time.time() - last_redeem if last_redeem == None or (time.time() - last_redeem
) >= redeem_delay: ) >= redeem_delay:
redeem_amount = decimal.Decimal(event["server" redeem_amount = decimal.Decimal(event["server"
].get_setting("redeem-amount", DEFAULT_REDEEM_AMOUNT)) ].get_setting("redeem-amount",
DEFAULT_REDEEM_AMOUNT))
event["user"].set_setting("coins", str( event["user"].set_setting("coins", str(
user_coins + redeem_amount)) user_coins + redeem_amount))
event["stdout"].write("Redeemed %s coins" % "{0:.2f}".format( event["stdout"].write("Redeemed %s coins" % "{0:.2f}".format(
@ -111,7 +117,8 @@ class Module(object):
else: else:
time_left = (last_redeem + redeem_delay) - time.time() time_left = (last_redeem + redeem_delay) - time.time()
event["stderr"].write("Please wait %s before redeeming" % event["stderr"].write("Please wait %s before redeeming" %
Utils.to_pretty_time(math.ceil(time_left))) Utils.to_pretty_time(
math.ceil(time_left)))
else: else:
event["stderr"].write( event["stderr"].write(
"You can only redeem coins when you have none") "You can only redeem coins when you have none")
@ -304,7 +311,8 @@ class Module(object):
return return
winnings_str = ["%s for %s (%d to 1)" % (winnings[bet][1], bet, winnings_str = ["%s for %s (%d to 1)" % (winnings[bet][1], bet,
winnings[bet][0]) for bet in winnings.keys()] winnings[bet][0]) for bet in
winnings.keys()]
coin_winnings = sum(bet[1] for bet in winnings.values()) coin_winnings = sum(bet[1] for bet in winnings.values())
coin_losses = sum([loss for loss in losses.values()]) coin_losses = sum([loss for loss in losses.values()])
@ -317,14 +325,22 @@ class Module(object):
choice = "%d %s" % (choice, colour) choice = "%d %s" % (choice, colour)
if not losses and winnings: if not losses and winnings:
event["stdout"].write("Roulette spin lands on %s, " event["stdout"].write("Roulette spin lands on %s, "
"%s wins %s%s" % (choice, event["user"].nickname, "%s wins %s%s" % (
", ".join(winnings_str), str(total_winnings_str))) choice, event["user"].nickname,
", ".join(winnings_str),
str(total_winnings_str)))
elif losses and winnings: elif losses and winnings:
event["stdout"].write("Roulette spin lands on %s, " event["stdout"].write("Roulette spin lands on %s, "
"%s wins %s%s; loses %s" % (choice, "%s wins %s%s; loses %s" % (choice,
event["user"].nickname, ", ".join(winnings_str), event[
str(total_winnings_str), str(coin_losses))) "user"].nickname,
", ".join(
winnings_str),
str(
total_winnings_str),
str(coin_losses)))
else: else:
event["stdout"].write("Roulette spin lands on %s, " event["stdout"].write("Roulette spin lands on %s, "
"%s loses %s" % (choice, event["user"].nickname, "%s loses %s" % (
choice, event["user"].nickname,
str(coin_losses))) str(coin_losses)))

View file

@ -8,42 +8,52 @@ OUT_CUTOFF = 400
REGEX_CUTOFF = re.compile("^.{1,%d}(?:\s|$)" % OUT_CUTOFF) REGEX_CUTOFF = re.compile("^.{1,%d}(?:\s|$)" % OUT_CUTOFF)
class Out(object): class Out(object):
def __init__(self, module_name, target): def __init__(self, module_name, target):
self.module_name = module_name self.module_name = module_name
self.target = target self.target = target
self._text = "" self._text = ""
self.written = False self.written = False
def write(self, text): def write(self, text):
self._text += text self._text += text
self.written = True self.written = True
return self return self
def send(self): def send(self):
if self.has_text(): if self.has_text():
text = self._text text = self._text
text_encoded = text.encode("utf8") text_encoded = text.encode("utf8")
if len(text_encoded) > OUT_CUTOFF: if len(text_encoded) > OUT_CUTOFF:
text = "%s%s" % (text_encoded[:OUT_CUTOFF].decode("utf8" text = "%s%s" % (text_encoded[:OUT_CUTOFF].decode("utf8"
).rstrip(), STR_MORE) ).rstrip(),
STR_MORE)
self._text = "%s%s" % (STR_CONTINUED, text_encoded[OUT_CUTOFF: self._text = "%s%s" % (STR_CONTINUED, text_encoded[OUT_CUTOFF:
].decode("utf8").lstrip()) ].decode("utf8").lstrip())
else: else:
self._text = "" self._text = ""
self.target.send_message(text, prefix="[%s] " % self.prefix()) self.target.send_message(text, prefix="[%s] " % self.prefix())
def set_prefix(self, prefix): def set_prefix(self, prefix):
self.module_name = prefix self.module_name = prefix
def has_text(self): def has_text(self):
return bool(self._text) return bool(self._text)
class StdOut(Out): class StdOut(Out):
def prefix(self): def prefix(self):
return "%s%s%s" % (Utils.color(Utils.COLOR_GREEN), return "%s%s%s" % (Utils.color(Utils.COLOR_GREEN),
self.module_name, Utils.FONT_RESET) self.module_name, Utils.FONT_RESET)
class StdErr(Out): class StdErr(Out):
def prefix(self): def prefix(self):
return "%s!%s%s" % (Utils.color(Utils.COLOR_RED), return "%s!%s%s" % (Utils.color(Utils.COLOR_RED),
self.module_name, Utils.FONT_RESET) self.module_name, Utils.FONT_RESET)
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -52,12 +62,15 @@ class Module(object):
bot.events.on("received").on("message").on("private").hook( bot.events.on("received").on("message").on("private").hook(
self.private_message) self.private_message)
bot.events.on("received").on("command").on("help").hook(self.help, bot.events.on("received").on("command").on("help").hook(self.help,
help="Show help for commands", usage="<command>") help="Show help for commands",
usage="<command>")
bot.events.on("received").on("command").on("usage").hook(self.usage, bot.events.on("received").on("command").on("usage").hook(self.usage,
help="Show usage help for commands", min_args=1, help="Show usage help for commands",
min_args=1,
usage="<command>") usage="<command>")
bot.events.on("received").on("command").on("more").hook(self.more, bot.events.on("received").on("command").on("more").hook(self.more,
help="Get more output from the last command", skip_out=True) help="Get more output from the last command",
skip_out=True)
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="command-prefix", "channelset").assure_call(setting="command-prefix",
@ -78,6 +91,7 @@ class Module(object):
def has_command(self, command): def has_command(self, command):
return command.lower() in self.bot.events.on("received").on( return command.lower() in self.bot.events.on("received").on(
"command").get_children() "command").get_children()
def get_hook(self, command): def get_hook(self, command):
return self.bot.events.on("received").on("command").on(command return self.bot.events.on("received").on("command").on(command
).get_hooks()[0] ).get_hooks()[0]
@ -85,7 +99,8 @@ class Module(object):
def is_highlight(self, server, s): def is_highlight(self, server, s):
return s.lower() == server.nickname_lower or (s.lower().startswith( return s.lower() == server.nickname_lower or (s.lower().startswith(
server.nickname_lower) and len(s) == len(server.nickname_lower server.nickname_lower) and len(s) == len(server.nickname_lower
)+1 and s[-1] in [":", ","]) ) + 1 and s[-1] in [":",
","])
def message(self, event, command, args_index=1): def message(self, event, command, args_index=1):
if self.has_command(command): if self.has_command(command):
@ -109,8 +124,13 @@ class Module(object):
target) target)
returns = self.bot.events.on("preprocess").on("command" returns = self.bot.events.on("preprocess").on("command"
).call(hook=hook, user=event["user"], server=event["server"], ).call(hook=hook,
target=target, is_channel=is_channel) user=event[
"user"],
server=event[
"server"],
target=target,
is_channel=is_channel)
for returned in returns: for returned in returns:
if returned: if returned:
stderr.write(returned).send() stderr.write(returned).send()
@ -130,7 +150,8 @@ class Module(object):
server = event["server"] server = event["server"]
user = event["user"] user = event["user"]
self.bot.events.on("received").on("command").on(command self.bot.events.on("received").on("command").on(command
).call_limited(1, user=user, server=server, ).call_limited(
1, user=user, server=server,
target=target, buffer=buffer, args=args, target=target, buffer=buffer, args=args,
args_split=args_split, stdout=stdout, stderr=stderr, args_split=args_split, stdout=stdout, stderr=stderr,
command=command.lower(), is_channel=is_channel) command=command.lower(), is_channel=is_channel)
@ -141,10 +162,12 @@ class Module(object):
target.last_stderr = stderr target.last_stderr = stderr
buffer.skip_next() buffer.skip_next()
def channel_message(self, event): def channel_message(self, event):
command_prefix = event["channel"].get_setting("command-prefix", command_prefix = event["channel"].get_setting("command-prefix",
event["server"].get_setting("command-prefix", "!")) event[
"server"].get_setting(
"command-prefix",
"!"))
if event["message_split"][0].startswith(command_prefix): if event["message_split"][0].startswith(command_prefix):
command = event["message_split"][0].replace( command = event["message_split"][0].replace(
command_prefix, "", 1).lower() command_prefix, "", 1).lower()
@ -164,17 +187,21 @@ class Module(object):
command = event["args_split"][0].lower() command = event["args_split"][0].lower()
if command in self.bot.events.on("received").on( if command in self.bot.events.on("received").on(
"command").get_children(): "command").get_children():
hooks = self.bot.events.on("received").on("command").on(command).get_hooks() hooks = self.bot.events.on("received").on("command").on(
command).get_hooks()
if hooks and "help" in hooks[0].kwargs: if hooks and "help" in hooks[0].kwargs:
event["stdout"].write("%s: %s" % (command, hooks[0].kwargs["help"])) event["stdout"].write(
"%s: %s" % (command, hooks[0].kwargs["help"]))
else: else:
event["stderr"].write("No help available for %s" % command) event["stderr"].write("No help available for %s" % command)
else: else:
event["stderr"].write("Unknown command '%s'" % command) event["stderr"].write("Unknown command '%s'" % command)
else: else:
help_available = [] help_available = []
for child in self.bot.events.on("received").on("command").get_children(): for child in self.bot.events.on("received").on(
hooks = self.bot.events.on("received").on("command").on(child).get_hooks() "command").get_children():
hooks = self.bot.events.on("received").on("command").on(
child).get_hooks()
if hooks and "help" in hooks[0].kwargs: if hooks and "help" in hooks[0].kwargs:
help_available.append(child) help_available.append(child)
help_available = sorted(help_available) help_available = sorted(help_available)
@ -184,16 +211,20 @@ class Module(object):
command = event["args_split"][0].lower() command = event["args_split"][0].lower()
if command in self.bot.events.on("received").on( if command in self.bot.events.on("received").on(
"command").get_children(): "command").get_children():
hooks = self.bot.events.on("received").on("command").on(command).get_hooks() hooks = self.bot.events.on("received").on("command").on(
command).get_hooks()
if hooks and "usage" in hooks[0].kwargs: if hooks and "usage" in hooks[0].kwargs:
event["stdout"].write("Usage: %s %s" % (command, hooks[0].kwargs["usage"])) event["stdout"].write(
"Usage: %s %s" % (command, hooks[0].kwargs["usage"]))
else: else:
event["stderr"].write("No usage help available for %s" % command) event["stderr"].write(
"No usage help available for %s" % command)
else: else:
event["stderr"].write("Unknown command '%s'" % command) event["stderr"].write("Unknown command '%s'" % command)
def more(self, event): def more(self, event):
if event["target"].last_stdout and event["target"].last_stdout.has_text(): if event["target"].last_stdout and event[
"target"].last_stdout.has_text():
event["target"].last_stdout.send() event["target"].last_stdout.send()
def send_stdout(self, event): def send_stdout(self, event):
@ -201,6 +232,7 @@ class Module(object):
stdout.write(event["message"]).send() stdout.write(event["message"]).send()
if stdout.has_text(): if stdout.has_text():
event["target"].last_stdout = stdout event["target"].last_stdout = stdout
def send_stderr(self, event): def send_stderr(self, event):
stderr = StdErr(event["module_name"], event["target"]) stderr = StdErr(event["module_name"], event["target"])
stderr.write(event["message"]).send() stderr.write(event["message"]).send()

View file

@ -1,5 +1,6 @@
import datetime import datetime
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("message").on("private").hook( bot.events.on("received").on("message").on("private").hook(

View file

@ -4,6 +4,7 @@ import Utils
URL_WORDNIK = "http://api.wordnik.com:80/v4/word.json/%s/definitions" URL_WORDNIK = "http://api.wordnik.com:80/v4/word.json/%s/definitions"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot

View file

@ -1,7 +1,9 @@
import socket import socket
class Module(object): class Module(object):
_name = "DNS" _name = "DNS"
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("dns").hook( bot.events.on("received").on("command").on("dns").hook(
self.dns, min_args=1, self.dns, min_args=1,

View file

@ -56,7 +56,8 @@ class Module(object):
for server in self.bot.servers.values(): for server in self.bot.servers.values():
for channel in server.channels.values(): for channel in server.channels.values():
ducks_enabled = channel.get_setting("ducks-enabled", 0) ducks_enabled = channel.get_setting("ducks-enabled", 0)
ducks_enabled = int(ducks_enabled) if isinstance(ducks_enabled, str) else ducks_enabled ducks_enabled = int(ducks_enabled) if isinstance(ducks_enabled,
str) else ducks_enabled
min_time = "min-duck-time-%s" % channel.name min_time = "min-duck-time-%s" % channel.name
max_time = "max-duck-time-%s" % channel.name max_time = "max-duck-time-%s" % channel.name
@ -64,8 +65,10 @@ class Module(object):
min_duck_time = channel.get_setting("min-duck-time", 240) min_duck_time = channel.get_setting("min-duck-time", 240)
max_duck_time = channel.get_setting("max-duck-time", 1200) max_duck_time = channel.get_setting("max-duck-time", 1200)
min_duck_time = int(min_duck_time) if isinstance(min_duck_time, str) else min_duck_time min_duck_time = int(min_duck_time) if isinstance(min_duck_time,
max_duck_time = int(max_duck_time) if isinstance(max_duck_time, str) else max_duck_time str) else min_duck_time
max_duck_time = int(max_duck_time) if isinstance(max_duck_time,
str) else max_duck_time
self.duck_times[min_time] = min_duck_time self.duck_times[min_time] = min_duck_time
self.duck_times[max_time] = max_duck_time self.duck_times[max_time] = max_duck_time
@ -84,25 +87,28 @@ class Module(object):
min = "min-duck-time-%s" % (channel_name) min = "min-duck-time-%s" % (channel_name)
max = "max-duck-time-%s" % (channel_name) max = "max-duck-time-%s" % (channel_name)
self.bot.log.debug("Attempting to set %s to %s", [str(min), str(self.duck_times[min])]); self.bot.log.debug("Attempting to set %s to %s",
self.bot.log.debug("Attempting to set %s to %s", [str(max), str(self.duck_times[max])]); [str(min), str(self.duck_times[min])]);
self.bot.log.debug("Attempting to set %s to %s",
[str(max), str(self.duck_times[max])]);
return random.randint(self.duck_times[min], self.duck_times[max]) return random.randint(self.duck_times[min], self.duck_times[max])
def decoy_time(self): def decoy_time(self):
return random.randint(300, 700) return random.randint(10, 20)
def duck_bef(self, event): def duck_bef(self, event):
target = event["user"].nickname target = event["user"].nickname
active_duck = event["target"].get_setting("active-duck", 0) active_duck = event["target"].get_setting("active-duck", 0)
active_duck = int(active_duck) if isinstance(active_duck, str) else active_duck active_duck = int(active_duck) if isinstance(active_duck,
str) else active_duck
if active_duck == 0: if active_duck == 0:
event["stderr"].set_prefix("Kick") event["stderr"].set_prefix("Kick")
if event["server"].has_user(target): if event["server"].has_user(target):
if not event["server"].is_own_nickname(target): if not event["server"].is_own_nickname(target):
event["target"].send_kick(target, "You tried befriending a non-existent duck. Creepy!") event["target"].send_kick(target,
"You tried befriending a non-existent duck. Creepy!")
else: else:
event["stderr"].write("Nope.") event["stderr"].write("Nope.")
else: else:
@ -116,8 +122,9 @@ class Module(object):
grammar = "" if befriended_ducks == 0 else "s" grammar = "" if befriended_ducks == 0 else "s"
event["stdout"].write( event["stdout"].write(
target + ", you've befriended " + str(befriended_ducks + 1) + " duck" + grammar + " in " + event[ target + ", you've befriended " + str(
"target"].name); befriended_ducks + 1) + " duck" + grammar + " in " + event[
"target"].name)
next_duck_time = self.duck_time(event) next_duck_time = self.duck_time(event)
self.bot.add_timer("duck-appear", next_duck_time, persist=False) self.bot.add_timer("duck-appear", next_duck_time, persist=False)
@ -128,7 +135,8 @@ class Module(object):
event["stderr"].set_prefix("Kick") event["stderr"].set_prefix("Kick")
if event["server"].has_user(target): if event["server"].has_user(target):
if not event["server"].is_own_nickname(target): if not event["server"].is_own_nickname(target):
event["target"].send_kick(target, "You tried shooting a non-existent duck. Creepy!") event["target"].send_kick(target,
"You tried shooting a non-existent duck. Creepy!")
else: else:
event["stderr"].write("Nope.") event["stderr"].write("Nope.")
else: else:
@ -142,7 +150,9 @@ class Module(object):
grammar = "" if shot_ducks == 0 else "s" grammar = "" if shot_ducks == 0 else "s"
event["stdout"].write( event["stdout"].write(
target + ", you've shot " + str(shot_ducks + 1) + " duck" + grammar + " in " + event["target"].name); target + ", you've shot " + str(
shot_ducks + 1) + " duck" + grammar + " in " + event[
"target"].name);
next_duck_time = self.duck_time(event) next_duck_time = self.duck_time(event)
self.bot.add_timer("duck-appear", next_duck_time, persist=False) self.bot.add_timer("duck-appear", next_duck_time, persist=False)
@ -151,13 +161,16 @@ class Module(object):
for server in self.bot.servers.values(): for server in self.bot.servers.values():
for channel in server.channels.values(): for channel in server.channels.values():
ducks_enabled = channel.get_setting("ducks-enabled", 0) ducks_enabled = channel.get_setting("ducks-enabled", 0)
ducks_enabled = int(ducks_enabled) if isinstance(ducks_enabled, str) else ducks_enabled ducks_enabled = int(ducks_enabled) if isinstance(ducks_enabled,
str) else ducks_enabled
if ducks_enabled == 0: if ducks_enabled == 0:
continue continue
self.bot.log.info("Ducks enabled for %s: %s", [str(channel.name), str(ducks_enabled)]) self.bot.log.info("Ducks enabled for %s: %s",
[str(channel.name), str(ducks_enabled)])
active_duck = channel.get_setting("active-duck", 0) active_duck = channel.get_setting("active-duck", 0)
active_duck = int(active_duck) if isinstance(active_duck, str) else active_duck active_duck = int(active_duck) if isinstance(active_duck,
str) else active_duck
if ducks_enabled == 1 and active_duck == 0: if ducks_enabled == 1 and active_duck == 0:
ducks = [ ducks = [
@ -181,7 +194,8 @@ class Module(object):
channel.set_setting("active-duck", 0) channel.set_setting("active-duck", 0)
next_duck_time = self.duck_time(channel.name) next_duck_time = self.duck_time(channel.name)
self.bot.add_timer("duck-appear", next_duck_time, persist=False) self.bot.add_timer("duck-appear", next_duck_time,
persist=False)
def duck_decoy(self, event): def duck_decoy(self, event):
ducks = [ ducks = [
@ -194,12 +208,15 @@ class Module(object):
"・ ゜・。 。・゜゜ \_ó< beep beep!" "・ ゜・。 。・゜゜ \_ó< beep beep!"
] ]
event["target"].send_message(random.choice(ducks)) event["channel"].send_message(random.choice(ducks))
def set_decoy(self, event): def set_decoy(self, event):
channel = event["target"]
next_decoy_time = self.decoy_time() next_decoy_time = self.decoy_time()
self.bot.events.on("timer").on("duck-decoy").hook(self.duck_decoy) self.bot.events.on("timer").on("duck-decoy").hook(self.duck_decoy)
self.bot.add_timer("duck-decoy", next_decoy_time, persist=False) self.bot.add_timer("duck-decoy", next_decoy_time, None, None, False,
channel=channel)
# def coins(self, event): # def coins(self, event):
# if event["args_split"]: # if event["args_split"]:

View file

@ -2,8 +2,10 @@ import Utils
URL_GEOIP = "http://ip-api.com/json/%s" URL_GEOIP = "http://ip-api.com/json/%s"
class Module(object): class Module(object):
_name = "GeoIP" _name = "GeoIP"
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("geoip").hook( bot.events.on("received").on("command").on("geoip").hook(
self.geoip, min_args=1, self.geoip, min_args=1,

View file

@ -5,11 +5,13 @@ import Utils
URL_GOOGLESEARCH = "https://www.googleapis.com/customsearch/v1" URL_GOOGLESEARCH = "https://www.googleapis.com/customsearch/v1"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("google", bot.events.on("received").on("command").on("google",
"g").hook(self.google, help="Google feeling lucky", "g").hook(self.google,
help="Google feeling lucky",
usage="[search term]") usage="[search term]")
def google(self, event): def google(self, event):

View file

@ -1,10 +1,12 @@
import hashlib import hashlib
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("hash" bot.events.on("received").on("command").on("hash"
).hook(self.hash, min_args=2, help="Hash a string", ).hook(self.hash, min_args=2,
help="Hash a string",
usage="<algo> <string>") usage="<algo> <string>")
def hash(self, event): def hash(self, event):

View file

@ -3,6 +3,7 @@ import Utils
URL_HAVEIBEENPWNEDAPI = "https://haveibeenpwned.com/api/v2/breachedaccount/%s" URL_HAVEIBEENPWNEDAPI = "https://haveibeenpwned.com/api/v2/breachedaccount/%s"
URL_HAVEIBEENPWNED = "https://haveibeenpwned.com/" URL_HAVEIBEENPWNED = "https://haveibeenpwned.com/"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("beenpwned").hook( bot.events.on("received").on("command").on("beenpwned").hook(
@ -17,7 +18,8 @@ class Module(object):
code, page = page code, page = page
if code == 200: if code == 200:
event["stdout"].write( event["stdout"].write(
"It seems '%s' has been pwned. check on %s." % (event["args"], "It seems '%s' has been pwned. check on %s." % (
event["args"],
URL_HAVEIBEENPWNED)) URL_HAVEIBEENPWNED))
else: else:
event["stdout"].write("It seems '%s' has not been pwned" % ( event["stdout"].write("It seems '%s' has not been pwned" % (

View file

@ -1,7 +1,6 @@
class Module(object): class Module(object):
_name = "IDs" _name = "IDs"
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received.command.myid").hook(self.my_id, bot.events.on("received.command.myid").hook(self.my_id,
help="Show your user ID") help="Show your user ID")

View file

@ -6,8 +6,10 @@ import Utils
URL_OMDB = "http://www.omdbapi.com/" URL_OMDB = "http://www.omdbapi.com/"
URL_IMDBTITLE = "http://imdb.com/title/%s" URL_IMDBTITLE = "http://imdb.com/title/%s"
class Module(object): class Module(object):
_name = "IMDb" _name = "IMDb"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("imdb").hook( bot.events.on("received").on("command").on("imdb").hook(

View file

@ -4,6 +4,7 @@ import Utils
SECONDS_MAX = Utils.SECONDS_WEEKS * 8 SECONDS_MAX = Utils.SECONDS_WEEKS * 8
SECONDS_MAX_DESCRIPTION = "8 weeks" SECONDS_MAX_DESCRIPTION = "8 weeks"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -20,8 +21,10 @@ class Module(object):
due_time = int(time.time()) + seconds due_time = int(time.time()) + seconds
self.bot.add_timer("in", seconds, self.bot.add_timer("in", seconds,
target=event["target"].name, due_time=due_time, target=event["target"].name,
server_id=event["server"].id, nickname=event["user"].nickname, due_time=due_time,
server_id=event["server"].id,
nickname=event["user"].nickname,
message=message) message=message)
event["stdout"].write("Saved") event["stdout"].write("Saved")
else: else:

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("numeric").on("001").hook(self.do_join) bot.events.on("received").on("numeric").on("001").hook(self.do_join)

View file

@ -4,6 +4,7 @@ import Utils
REGEX_KARMA = re.compile("(.*)(\+{2,}|\-{2,})$") REGEX_KARMA = re.compile("(.*)(\+{2,}|\-{2,})$")
KARMA_DELAY_SECONDS = 3 KARMA_DELAY_SECONDS = 3
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -52,10 +53,13 @@ class Module(object):
event["user"].last_karma = time.time() event["user"].last_karma = time.time()
elif verbose: elif verbose:
if target: if target:
self.bot.events.on("send").on("stderr").call(module_name="Karma", self.bot.events.on("send").on("stderr").call(
target=event["channel"], message="You cannot change your own karma") module_name="Karma",
target=event["channel"],
message="You cannot change your own karma")
elif verbose: elif verbose:
event["stderr"].write("Try again in a couple of seconds") event["stderr"].write("Try again in a couple of seconds")
def karma(self, event): def karma(self, event):
if event["args"]: if event["args"]:
target = event["args"] target = event["args"]

View file

@ -4,6 +4,7 @@ import Utils
URL_SCROBBLER = "http://ws.audioscrobbler.com/2.0/" URL_SCROBBLER = "http://ws.audioscrobbler.com/2.0/"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -13,7 +14,8 @@ class Module(object):
help="Set username on last.fm") help="Set username on last.fm")
bot.events.on("received").on("command").on("np", bot.events.on("received").on("command").on("np",
"listening", "nowplaying").hook(self.np, "listening",
"nowplaying").hook(self.np,
help="Get the last listened to track from a user", help="Get the last listened to track from a user",
usage="[username]") usage="[username]")

View file

@ -1,27 +1,38 @@
# --ignore # --ignore
import types, json import types, json
def get_target(user): def get_target(user):
return user.alias or user.nickname return user.alias or user.nickname
def set_setting(user, setting, value): def set_setting(user, setting, value):
target = get_target(user) target = get_target(user)
user.bot.database.set_user_setting(user.server.id, target, user.bot.database.set_user_setting(user.server.id, target,
setting, value) setting, value)
def get_setting(user, setting, default=None): def get_setting(user, setting, default=None):
target = get_target(user) target = get_target(user)
return user.bot.database.get_user_setting(user.server.id, return user.bot.database.get_user_setting(user.server.id,
target, setting, default) target, setting, default)
def find_settings(user, pattern, default=[]): def find_settings(user, pattern, default=[]):
target = get_target(user) target = get_target(user)
return user.bot.databse.find_user_settings(user.server.id, return user.bot.databse.find_user_settings(user.server.id,
target, pattern, default) target, pattern, default)
def del_setting(user, setting): def del_setting(user, setting):
target = get_target(user) target = get_target(user)
user.bot.database.del_user_setting(user.server.id, target, user.bot.database.del_user_setting(user.server.id, target,
setting) setting)
class Module(object): class Module(object):
_name = "Aliases" _name = "Aliases"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("new").on("user").hook(self.new_user) bot.events.on("new").on("user").hook(self.new_user)
@ -60,6 +71,7 @@ class Module(object):
FROM user_settings WHERE setting='alias' AND value=? FROM user_settings WHERE setting='alias' AND value=?
AND server_id=?""", [json.dumps(target.lower()), AND server_id=?""", [json.dumps(target.lower()),
server.id]).fetchall() server.id]).fetchall()
def _change_nick(self, old_nickname, new_nickname): def _change_nick(self, old_nickname, new_nickname):
self.bot.database.cursor().execute("""UPDATE user_settings self.bot.database.cursor().execute("""UPDATE user_settings
SET nickname=? WHERE nickname=?""", [new_nickname.lower(), SET nickname=? WHERE nickname=?""", [new_nickname.lower(),
@ -76,7 +88,9 @@ class Module(object):
aliases = self._get_aliases(target, event["server"]) aliases = self._get_aliases(target, event["server"])
if any(aliases): if any(aliases):
event["stdout"].write("Aliases for %s: %s" % (target, event["stdout"].write("Aliases for %s: %s" % (target,
", ".join([a[0] for a in aliases]))) ", ".join(
[a[0] for a in
aliases])))
else: else:
event["stderr"].write("%s has no aliases" % target) event["stderr"].write("%s has no aliases" % target)

View file

@ -1,13 +1,18 @@
import base64 import base64
import EventManager import EventManager
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("numeric").on("001" bot.events.on("received").on("numeric").on("001"
).hook(self.on_connect, priority=EventManager.PRIORITY_URGENT) ).hook(self.on_connect,
priority=EventManager.PRIORITY_URGENT)
bot.events.on("received").on("command").on("setnickserv" bot.events.on("received").on("command").on("setnickserv"
).hook(self.set_nickserv, min_args=1, permission="setnickserv", ).hook(self.set_nickserv,
help="Set bot's nickserv password", usage="<password>", min_args=1,
permission="setnickserv",
help="Set bot's nickserv password",
usage="<password>",
private_only=True) private_only=True)
def on_connect(self, event): def on_connect(self, event):

View file

@ -14,21 +14,25 @@ from suds import WebFault
URL = 'https://lite.realtime.nationalrail.co.uk/OpenLDBSVWS/wsdl.aspx?ver=2016-02-16' URL = 'https://lite.realtime.nationalrail.co.uk/OpenLDBSVWS/wsdl.aspx?ver=2016-02-16'
class Module(object): class Module(object):
_name = "NR" _name = "NR"
PASSENGER_ACTIVITIES = ["U", "P", "R"] PASSENGER_ACTIVITIES = ["U", "P", "R"]
COLOURS = [Utils.COLOR_LIGHTBLUE, Utils.COLOR_GREEN, Utils.COLOR_RED, Utils.COLOR_CYAN, Utils.COLOR_LIGHTGREY, Utils.COLOR_ORANGE] COLOURS = [Utils.COLOR_LIGHTBLUE, Utils.COLOR_GREEN, Utils.COLOR_RED,
Utils.COLOR_CYAN, Utils.COLOR_LIGHTGREY, Utils.COLOR_ORANGE]
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self._client = None self._client = None
bot.events.on("received").on("command").on("nrtrains" bot.events.on("received").on("command").on("nrtrains"
).hook(self.trains, min_args=1, ).hook(self.trains,
min_args=1,
help="Get train/bus services for a station (Powered by NRE)", help="Get train/bus services for a station (Powered by NRE)",
usage="<crs_id>") usage="<crs_id>")
bot.events.on("received").on("command").on("nrservice" bot.events.on("received").on("command").on("nrservice"
).hook(self.service, min_args=1, ).hook(self.service,
min_args=1,
help="Get train service information for a UID, headcode or RID (Powered by NRE)", help="Get train service information for a UID, headcode or RID (Powered by NRE)",
usage="<service_id>") usage="<service_id>")
bot.events.on("received").on("command").on("nrhead" bot.events.on("received").on("command").on("nrhead"
@ -36,13 +40,16 @@ class Module(object):
help="Get information for a given headcode/UID/RID (Powered by NRE)", help="Get information for a given headcode/UID/RID (Powered by NRE)",
usage="<headcode>") usage="<headcode>")
bot.events.on("received").on("command").on("nrcode" bot.events.on("received").on("command").on("nrcode"
).hook(self.service_code, min_args=1, ).hook(self.service_code,
min_args=1,
help="Get the text for a given delay/cancellation code (Powered by NRE)", help="Get the text for a given delay/cancellation code (Powered by NRE)",
usage="<code>") usage="<code>")
bot.events.on("telegram").on("command").on("nrtrains").hook(self.trains) bot.events.on("telegram").on("command").on("nrtrains").hook(self.trains)
bot.events.on("telegram").on("command").on("nrcode").hook(self.service_code) bot.events.on("telegram").on("command").on("nrcode").hook(
self.service_code)
bot.events.on("telegram").on("command").on("nrhead").hook(self.head) bot.events.on("telegram").on("command").on("nrhead").hook(self.head)
bot.events.on("telegram").on("command").on("nrservice").hook(self.service) bot.events.on("telegram").on("command").on("nrservice").hook(
self.service)
@property @property
def client(self): def client(self):
@ -83,7 +90,8 @@ class Module(object):
continue continue
ret["default"] = False ret["default"] = False
ret[k] = v if len(defaults[k]) == 2 else defaults[k][2](v) ret[k] = v if len(defaults[k]) == 2 else defaults[k][2](v)
ret["errors_summary"] = ", ".join(['"%s": %s' % (a[0], a[1]) for a in ret["errors"]]) ret["errors_summary"] = ", ".join(
['"%s": %s' % (a[0], a[1]) for a in ret["errors"]])
return ret return ret
def process(self, service): def process(self, service):
@ -100,10 +108,12 @@ class Module(object):
times[a] = {"orig": service[a]} times[a] = {"orig": service[a]}
if len(service[a]) > 5: if len(service[a]) > 5:
times[a]["datetime"] = datetime.strptime(service[a], "%Y-%m-%dT%H:%M:%S") times[a]["datetime"] = datetime.strptime(service[a],
"%Y-%m-%dT%H:%M:%S")
else: else:
times[a]["datetime"] = datetime.strptime( times[a]["datetime"] = datetime.strptime(
datetime.now().date().isoformat() + "T" + service[a][:4], datetime.now().date().isoformat() + "T" + service[a][
:4],
"%Y-%m-%dT%H%M" "%Y-%m-%dT%H%M"
) )
times[a]["ut"] = times[a]["datetime"].timestamp() times[a]["ut"] = times[a]["datetime"].timestamp()
@ -112,8 +122,10 @@ class Module(object):
for k, a in times.items(): for k, a in times.items():
if not a["orig"]: continue if not a["orig"]: continue
a["short"] = a["datetime"].strftime("%H%M") if len(a["orig"]) > 5 else a["orig"] a["short"] = a["datetime"].strftime("%H%M") if len(
a["shortest"] = "%02d" % a["datetime"].minute if -300 < a["ut"]-ut_now < 1800 else a["short"] a["orig"]) > 5 else a["orig"]
a["shortest"] = "%02d" % a["datetime"].minute if -300 < a[
"ut"] - ut_now < 1800 else a["short"]
a["prefix"] = k[2] + ("s" if k[0] == "s" else "") a["prefix"] = k[2] + ("s" if k[0] == "s" else "")
a["estimate"] = k[0] == "e" a["estimate"] = k[0] == "e"
a["schedule"] = k[0] == "s" a["schedule"] = k[0] == "s"
@ -122,7 +134,10 @@ class Module(object):
if "a" + k[1:] in service: a["status"] = {"d": 0, "a": 3}[k[2]] if "a" + k[1:] in service: a["status"] = {"d": 0, "a": 3}[k[2]]
if k[0] == "s": a["status"] = 4 if k[0] == "s": a["status"] = 4
arr, dep = [times[a] for a in a_types if times[a]["ut"]], [times[a] for a in d_types if times[a]["ut"]] arr, dep = [times[a] for a in a_types if times[a]["ut"]], [times[a] for
a in d_types
if times[a][
"ut"]]
times["arrival"] = (arr + dep + [nonetime])[0] times["arrival"] = (arr + dep + [nonetime])[0]
times["departure"] = (dep + arr + [nonetime])[0] times["departure"] = (dep + arr + [nonetime])[0]
times["a"], times["d"] = (arr + [nonetime])[0], (dep + [nonetime])[0] times["a"], times["d"] = (arr + [nonetime])[0], (dep + [nonetime])[0]
@ -130,9 +145,13 @@ class Module(object):
times["max_sched"] = {"ut": max(times["sta"]["ut"], times["std"]["ut"])} times["max_sched"] = {"ut": max(times["sta"]["ut"], times["std"]["ut"])}
return times return times
def activities(self, string): return [a+b.strip() for a,b in list(zip(*[iter(string)]*2)) if (a+b).strip()] def activities(self, string):
return [a + b.strip() for a, b in list(zip(*[iter(string)] * 2)) if
(a + b).strip()]
def reduced_activities(self, string): return [a for a in self.activities(string) if a in self.PASSENGER_ACTIVITIES] def reduced_activities(self, string):
return [a for a in self.activities(string) if
a in self.PASSENGER_ACTIVITIES]
def trains(self, event): def trains(self, event):
client = self.client client = self.client
@ -143,22 +162,42 @@ class Module(object):
schedule = {} schedule = {}
location_code = event["args_split"][0].upper() location_code = event["args_split"][0].upper()
filter = self.filter(' '.join(event["args_split"][1:]) if len(event["args_split"]) > 1 else "", { filter = self.filter(' '.join(event["args_split"][1:]) if len(
"dest": ('', lambda x: x.isalpha() and len(x)==3), event["args_split"]) > 1 else "", {
"origin":('', lambda x: x.isalpha() and len(x)==3), "dest": (
"inter": ('', lambda x: x.isalpha() and len(x)==3, lambda x: x.upper()), '', lambda x: x.isalpha() and len(x) == 3),
"toc": ('', lambda x: x.isalpha() and len(x) == 2), "origin": (
"dedup": (False, lambda x: type(x)==type(True)), '', lambda x: x.isalpha() and len(x) == 3),
"inter": (
'', lambda x: x.isalpha() and len(x) == 3,
lambda x: x.upper()),
"toc": (
'', lambda x: x.isalpha() and len(x) == 2),
"dedup": (
False, lambda x: type(x) == type(True)),
"plat": ('', lambda x: len(x) <= 3), "plat": ('', lambda x: len(x) <= 3),
"type": ("departure", lambda x: x in ["departure", "arrival", "both"]), "type": ("departure",
"terminating": (False, lambda x: type(x)==type(True)), lambda x: x in ["departure",
"period": (120, lambda x: x.isdigit() and 1 <= int(x) <= 480, lambda x: int(x)), "arrival", "both"]),
"nonpassenger": (False, lambda x: type(x)==type(True)), "terminating": (
"time": ("", lambda x: len(x)==4 and x.isdigit()), False, lambda x: type(x) == type(True)),
"period": (120,
lambda x: x.isdigit() and 1 <= int(
x) <= 480, lambda x: int(x)),
"nonpassenger": (
False, lambda x: type(x) == type(True)),
"time": (
"", lambda x: len(x) == 4 and x.isdigit()),
"date": ("", lambda x: len(x) == 10), "date": ("", lambda x: len(x) == 10),
"tops": (None, lambda x: len(x)<4 and x.isdigit()), "tops": (
"power": (None, lambda x: x.upper() in ["EMU", "DMU", "HST", "D", "E"], lambda x: x.upper()), None, lambda x: len(x) < 4 and x.isdigit()),
"crs": (False, lambda x: type(x)==type(True)), "power": (None,
lambda x: x.upper() in ["EMU", "DMU",
"HST", "D",
"E"],
lambda x: x.upper()),
"crs": (
False, lambda x: type(x) == type(True)),
"st": (False, lambda x: type(x) == type(True)) "st": (False, lambda x: type(x) == type(True))
}) })
@ -166,7 +205,8 @@ class Module(object):
return event["stderr"].write("Filter: " + filter["errors_summary"]) return event["stderr"].write("Filter: " + filter["errors_summary"])
if filter["inter"] and filter["type"] != "departure": if filter["inter"] and filter["type"] != "departure":
return event["stderr"].write("Filtering by intermediate stations is only supported for departures.") return event["stderr"].write(
"Filtering by intermediate stations is only supported for departures.")
nr_filterlist = client.factory.create("filterList") nr_filterlist = client.factory.create("filterList")
if filter["inter"]: nr_filterlist.crs.append(filter["inter"]) if filter["inter"]: nr_filterlist.crs.append(filter["inter"])
@ -177,29 +217,40 @@ class Module(object):
now = now.replace(minute=int(filter["time"][2:])) now = now.replace(minute=int(filter["time"][2:]))
if filter["date"]: if filter["date"]:
newdate = datetime.strptime(filter["date"], "%Y-%m-%d").date() newdate = datetime.strptime(filter["date"], "%Y-%m-%d").date()
now = now.replace(day=newdate.day, month=newdate.month, year=newdate.year) now = now.replace(day=newdate.day, month=newdate.month,
year=newdate.year)
method = client.service.GetArrivalDepartureBoardByCRS if len(location_code) == 3 else client.service.GetArrivalDepartureBoardByTIPLOC method = client.service.GetArrivalDepartureBoardByCRS if len(
location_code) == 3 else client.service.GetArrivalDepartureBoardByTIPLOC
try: try:
query = method(100, location_code, now.isoformat().split(".")[0], filter["period"], query = method(100, location_code, now.isoformat().split(".")[0],
nr_filterlist, "to", '', "PBS", filter["nonpassenger"]) filter["period"],
nr_filterlist, "to", '', "PBS",
filter["nonpassenger"])
except WebFault as detail: except WebFault as detail:
if str(detail) == "Server raised fault: 'Invalid crs code supplied'": if str(
detail) == "Server raised fault: 'Invalid crs code supplied'":
return event["stderr"].write("Invalid CRS code.") return event["stderr"].write("Invalid CRS code.")
else: else:
return event["stderr"].write("An error occurred.") return event["stderr"].write("An error occurred.")
nrcc_severe = len([a for a in query["nrccMessages"][0] if a["severity"] == "Major"]) if "nrccMessages" in query else 0 nrcc_severe = len([a for a in query["nrccMessages"][0] if a[
"severity"] == "Major"]) if "nrccMessages" in query else 0
if event.get("external"): if event.get("external"):
station_summary = "%s (%s) - %s (%s):\n" % (query["locationName"], query["crs"], query["stationManager"], station_summary = "%s (%s) - %s (%s):\n" % (
query["locationName"], query["crs"], query["stationManager"],
query["stationManagerCode"]) query["stationManagerCode"])
else: else:
station_summary = "%s (%s, %s%s)" % (query["locationName"], query["crs"], query["stationManagerCode"], station_summary = "%s (%s, %s%s)" % (
", %s%s severe messages%s" % (Utils.color(Utils.COLOR_RED), nrcc_severe, Utils.color(Utils.FONT_RESET)) if nrcc_severe else "" query["locationName"], query["crs"], query["stationManagerCode"],
", %s%s severe messages%s" % (
Utils.color(Utils.COLOR_RED), nrcc_severe,
Utils.color(Utils.FONT_RESET)) if nrcc_severe else ""
) )
if not "trainServices" in query and not "busServices" in query and not "ferryServices" in query: if not "trainServices" in query and not "busServices" in query and not "ferryServices" in query:
return event["stdout"].write("%s: No services for the next %s minutes" % ( return event["stdout"].write(
"%s: No services for the next %s minutes" % (
station_summary, filter["period"])) station_summary, filter["period"]))
trains = [] trains = []
@ -213,103 +264,148 @@ class Module(object):
"uid": t["uid"], "uid": t["uid"],
"head": t["trainid"], "head": t["trainid"],
"platform": '?' if not "platform" in t else t["platform"], "platform": '?' if not "platform" in t else t["platform"],
"platform_hidden": "platformIsHidden" in t and t["platformIsHidden"], "platform_hidden": "platformIsHidden" in t and t[
"platformIsHidden"],
"platform_prefix": "", "platform_prefix": "",
"toc": t["operatorCode"], "toc": t["operatorCode"],
"cancelled": t["isCancelled"] if "isCancelled" in t else False, "cancelled": t["isCancelled"] if "isCancelled" in t else False,
"delayed" : t["departureType"]=="Delayed" if "departureType" in t else None, "delayed": t[
"cancel_reason" : t["cancelReason"]["value"] if "cancelReason" in t else "", "departureType"] == "Delayed" if "departureType" in t else None,
"delay_reason" : t["delayReason"]["value"] if "delayReason" in t else "", "cancel_reason": t["cancelReason"][
"value"] if "cancelReason" in t else "",
"delay_reason": t["delayReason"][
"value"] if "delayReason" in t else "",
"terminating": not "std" in t and not "etd" in t and not "atd" in t, "terminating": not "std" in t and not "etd" in t and not "atd" in t,
"bus": t["trainid"] == "0B00", "bus": t["trainid"] == "0B00",
"times": self.process(t), "times": self.process(t),
"activity": self.reduced_activities(t["activities"]), "activity": self.reduced_activities(t["activities"]),
} }
parsed["destinations"] = [{"name": a["locationName"], "tiploc": a["tiploc"], parsed["destinations"] = [
"crs": a["crs"] if "crs" in a else '', "code": a["crs"] if "crs" {"name": a["locationName"], "tiploc": a["tiploc"],
in a else a["tiploc"], "via": a["via"] if "via" in a else ''} "crs": a["crs"] if "crs" in a else '',
"code": a["crs"] if "crs"
in a else a["tiploc"],
"via": a["via"] if "via" in a else ''}
for a in t["destination"][0]] for a in t["destination"][0]]
parsed["origins"] = [{"name": a["locationName"], "tiploc": a["tiploc"], parsed["origins"] = [
"crs": a["crs"] if "crs" in a else '', "code": a["crs"] if "crs" {"name": a["locationName"], "tiploc": a["tiploc"],
in a else a["tiploc"], "via": a["via"] if "via" in a else ''} "crs": a["crs"] if "crs" in a else '',
"code": a["crs"] if "crs"
in a else a["tiploc"],
"via": a["via"] if "via" in a else ''}
for a in t["origin"][0]] for a in t["origin"][0]]
parsed["departure_only"] = location_code in [a["code"] for a in parsed["origins"]] parsed["departure_only"] = location_code in [a["code"] for a in
parsed["origins"]]
if parsed["cancelled"] or parsed["delayed"]: if parsed["cancelled"] or parsed["delayed"]:
for k, time in parsed["times"].items(): for k, time in parsed["times"].items():
time["short"], time["on_time"], time["status"], time["prefix"] = ( time["short"], time["on_time"], time["status"], time[
"%s:%s" % ("C" if parsed["cancel_reason"] else "D", parsed["cancel_reason"] or parsed["delay_reason"] or "?"), "prefix"] = (
"%s:%s" % ("C" if parsed["cancel_reason"] else "D",
parsed["cancel_reason"] or parsed[
"delay_reason"] or "?"),
False, 2, "" False, 2, ""
) )
trains.append(parsed) trains.append(parsed)
if eagle_url: if eagle_url:
summary_query = Utils.get_url("%s/json/summaries/%s?uids=%s" % (eagle_url, now.date().isoformat(), "%20".join([a["uid"] for a in trains])), json=True, headers={"x-eagle-key": self.bot.config["eagle-api-key"]}) summary_query = Utils.get_url("%s/json/summaries/%s?uids=%s" % (
eagle_url, now.date().isoformat(),
"%20".join([a["uid"] for a in trains])), json=True, headers={
"x-eagle-key": self.bot.config["eagle-api-key"]})
if summary_query: if summary_query:
for t in trains: for t in trains:
summary = summary_query[t["uid"]] summary = summary_query[t["uid"]]
t.update(summary) t.update(summary)
summary_plat = summary.get("platforms", {}).get(query["crs"]) summary_plat = summary.get("platforms", {}).get(
query["crs"])
if summary_plat and t["platform"] == "?": if summary_plat and t["platform"] == "?":
t["platform"], t["platform_prefix"] = summary_plat, "s" t["platform"], t["platform_prefix"] = summary_plat, "s"
for t in trains: for t in trains:
t["dest_summary"] = "/".join(["%s%s" %(a["code"]*filter["crs"] or a["name"], " " + a["via"] t["dest_summary"] = "/".join(["%s%s" % (
a["code"] * filter["crs"] or a["name"], " " + a["via"]
if a["via"] else '') for a in t["destinations"]]) if a["via"] else '') for a in t["destinations"]])
t["origin_summary"] = "/".join(["%s%s" %(a["code"]*filter["crs"] or a["name"], " " + a["via"] t["origin_summary"] = "/".join(["%s%s" % (
a["code"] * filter["crs"] or a["name"], " " + a["via"]
if a["via"] else '') for a in t["origins"]]) if a["via"] else '') for a in t["origins"]])
trains = sorted(trains, key=lambda t: t["times"]["max_sched"]["ut"] if filter["type"]=="both" else t["times"]["st" + filter["type"][0]]["ut"]) trains = sorted(trains,
key=lambda t: t["times"]["max_sched"]["ut"] if filter[
"type"] == "both" else
t["times"]["st" + filter["type"][0]]["ut"])
trains_filtered = [] trains_filtered = []
train_locs_toc = [] train_locs_toc = []
for train in trains: for train in trains:
if not True in [ if not True in [
(train["destinations"], train["toc"]) in train_locs_toc and (filter["dedup"] or filter["default"]), (train["destinations"], train["toc"]) in train_locs_toc and (
filter["dest"] and not filter["dest"].upper() in [a["code"] for a in train["destinations"]], filter["dedup"] or filter["default"]),
filter["origin"] and not filter["origin"].upper() in [a["code"] for a in train["origins"]], filter["dest"] and not filter["dest"].upper() in [a["code"] for
a in train[
"destinations"]],
filter["origin"] and not filter["origin"].upper() in [a["code"]
for a in
train[
"origins"]],
filter["toc"] and not filter["toc"].upper() == train["toc"], filter["toc"] and not filter["toc"].upper() == train["toc"],
filter["plat"] and not filter["plat"] == train["platform"], filter["plat"] and not filter["plat"] == train["platform"],
filter["type"] == "departure" and train["terminating"], filter["type"] == "departure" and train["terminating"],
filter["type"] == "arrival" and train["departure_only"], filter["type"] == "arrival" and train["departure_only"],
filter["terminating"] and not train["terminating"], filter["terminating"] and not train["terminating"],
filter["tops"] and not filter["tops"] in train.get("tops_possible", []), filter["tops"] and not filter["tops"] in train.get(
filter["power"] and not filter["power"]==train.get("power_type", None), "tops_possible", []),
filter["power"] and not filter["power"] == train.get(
"power_type", None),
]: ]:
train_locs_toc.append((train["destinations"], train["toc"])) train_locs_toc.append((train["destinations"], train["toc"]))
trains_filtered.append(train) trains_filtered.append(train)
if event.get("external"): if event.get("external"):
trains_string = "\n".join(["%-6s %-4s %-2s %-3s %1s%-6s %1s %s" % ( trains_string = "\n".join(["%-6s %-4s %-2s %-3s %1s%-6s %1s %s" % (
t["uid"], t["head"], t["toc"], "bus" if t["bus"] else t["platform"], t["uid"], t["head"], t["toc"],
"bus" if t["bus"] else t["platform"],
"~" if t["times"]["both"]["estimate"] else '', "~" if t["times"]["both"]["estimate"] else '',
t["times"]["both"]["prefix"] + t["times"]["both"]["short"], t["times"]["both"]["prefix"] + t["times"]["both"]["short"],
"" if t["terminating"] or filter["type"] == "arrival" else "", "" if t["terminating"] or filter["type"] == "arrival" else "",
t["origin_summary"] if t["terminating"] or filter["type"]=="arrival" else t["dest_summary"] t["origin_summary"] if t["terminating"] or filter[
"type"] == "arrival" else t["dest_summary"]
) for t in trains_filtered]) ) for t in trains_filtered])
else: else:
trains_string = ", ".join(["%s%s (%s, %s%s%s%s, %s%s%s%s%s)" % ( trains_string = ", ".join(["%s%s (%s, %s%s%s%s, %s%s%s%s%s)" % (
"from " if not filter["type"][0] in "ad" and t["terminating"] else '', "from " if not filter["type"][0] in "ad" and t[
t["origin_summary"] if t["terminating"] or filter["type"]=="arrival" else t["dest_summary"], "terminating"] else '',
t["origin_summary"] if t["terminating"] or filter[
"type"] == "arrival" else t["dest_summary"],
t["uid"], t["uid"],
t["platform_prefix"], t["platform_prefix"],
"bus" if t["bus"] else t["platform"], "bus" if t["bus"] else t["platform"],
"*" if t["platform_hidden"] else '', "*" if t["platform_hidden"] else '',
"?" if "platformsAreUnreliable" in query and query["platformsAreUnreliable"] else '', "?" if "platformsAreUnreliable" in query and query[
t["times"][filter["type"]]["prefix"].replace(filter["type"][0], '') if not t["cancelled"] else "", "platformsAreUnreliable"] else '',
t["times"][filter["type"]]["prefix"].replace(filter["type"][0],
'') if not t[
"cancelled"] else "",
Utils.color(colours[t["times"][filter["type"]]["status"]]), Utils.color(colours[t["times"][filter["type"]]["status"]]),
t["times"][filter["type"]]["shortest"*filter["st"] or "short"], t["times"][filter["type"]][
"shortest" * filter["st"] or "short"],
Utils.color(Utils.FONT_RESET), Utils.color(Utils.FONT_RESET),
bool(t["activity"]) * ", " + "+".join(t["activity"]), bool(t["activity"]) * ", " + "+".join(t["activity"]),
) for t in trains_filtered]) ) for t in trains_filtered])
if event.get("external"): if event.get("external"):
event["stdout"].write("%s%s\n%s" % ( event["stdout"].write("%s%s\n%s" % (
station_summary, "\n calling at %s" % filter["inter"] if filter["inter"] else '', trains_string)) station_summary,
"\n calling at %s" % filter["inter"] if filter["inter"] else '',
trains_string))
else: else:
event["stdout"].write("%s%s: %s" % (station_summary, " departures calling at %s" % filter["inter"] if filter["inter"] else '', trains_string)) event["stdout"].write("%s%s: %s" % (station_summary,
" departures calling at %s" %
filter["inter"] if filter[
"inter"] else '',
trains_string))
def service(self, event): def service(self, event):
client = self.client client = self.client
@ -317,7 +413,8 @@ class Module(object):
external = event.get("external", False) external = event.get("external", False)
SCHEDULE_STATUS = {"B": "perm bus", "F": "freight train", "P": "train", SCHEDULE_STATUS = {"B": "perm bus", "F": "freight train", "P": "train",
"S": "ship", "T": "trip", "1": "train", "2": "freight", "S": "ship", "T": "trip", "1": "train",
"2": "freight",
"3": "trip", "4": "ship", "5": "bus"} "3": "trip", "4": "ship", "5": "bus"}
eagle_key = self.bot.config["eagle-api-key"] eagle_key = self.bot.config["eagle-api-key"]
@ -327,9 +424,12 @@ class Module(object):
service_id = event["args_split"][0] service_id = event["args_split"][0]
filter = self.filter(' '.join(event["args_split"][1:]) if len(event["args_split"]) > 1 else "", { filter = self.filter(' '.join(event["args_split"][1:]) if len(
"passing": (False, lambda x: type(x)==type(True)), event["args_split"]) > 1 else "", {
"type": ("arrival", lambda x: x in ["arrival", "departure"]) "passing": (
False, lambda x: type(x) == type(True)),
"type": ("arrival", lambda x: x in ["arrival",
"departure"])
}) })
if filter["errors"]: if filter["errors"]:
@ -338,18 +438,27 @@ class Module(object):
rid = service_id rid = service_id
if len(service_id) <= 8: if len(service_id) <= 8:
query = client.service.QueryServices(service_id, datetime.utcnow().date().isoformat(), query = client.service.QueryServices(service_id,
datetime.utcnow().time().strftime("%H:%M:%S+0000")) datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime(
"%H:%M:%S+0000"))
if eagle_url: if eagle_url:
schedule_query = Utils.get_url("%s/json/schedule/%s/%s" % (eagle_url, service_id, datetime.now().date().isoformat()), json=True, headers={"x-eagle-key": eagle_key}) schedule_query = Utils.get_url("%s/json/schedule/%s/%s" % (
eagle_url, service_id, datetime.now().date().isoformat()),
json=True, headers={
"x-eagle-key": eagle_key})
if schedule_query: if schedule_query:
schedule = schedule_query["current"] schedule = schedule_query["current"]
if not query and not schedule: if not query and not schedule:
return event["stdout"].write("No service information is available for this identifier.") return event["stdout"].write(
"No service information is available for this identifier.")
if query and len(query["serviceList"][0]) > 1: if query and len(query["serviceList"][0]) > 1:
return event["stdout"].write("Identifier refers to multiple services: " + return event["stdout"].write(
", ".join(["%s (%s->%s)" % (a["uid"], a["originCrs"], a["destinationCrs"]) for a in query["serviceList"][0]])) "Identifier refers to multiple services: " +
", ".join(["%s (%s->%s)" % (
a["uid"], a["originCrs"], a["destinationCrs"]) for a in
query["serviceList"][0]]))
if query: rid = query["serviceList"][0][0]["rid"] if query: rid = query["serviceList"][0][0]["rid"]
if query: if query:
@ -357,70 +466,109 @@ class Module(object):
query = client.service.GetServiceDetailsByRID(rid) query = client.service.GetServiceDetailsByRID(rid)
if schedule: if schedule:
sources.append("Eagle/SCHEDULE") sources.append("Eagle/SCHEDULE")
if not query: query = {"trainid": schedule["signalling_id"] or "0000", "operator": schedule["operator_name"] or schedule["atoc_code"]} if not query: query = {
stype = "class %s %s" % (schedule_query["tops_inferred"], schedule["power_type"]) if schedule_query["tops_inferred"] else schedule["power_type"] "trainid": schedule["signalling_id"] or "0000",
"operator": schedule["operator_name"] or schedule[
"atoc_code"]}
stype = "class %s %s" % (
schedule_query["tops_inferred"], schedule["power_type"]) if \
schedule_query["tops_inferred"] else schedule["power_type"]
for k, v in { for k, v in {
"operatorCode": schedule["atoc_code"], "operatorCode": schedule["atoc_code"],
"serviceType": stype if stype else SCHEDULE_STATUS[schedule["status"]], "serviceType": stype if stype else SCHEDULE_STATUS[
schedule["status"]],
}.items(): }.items():
query[k] = v query[k] = v
disruptions = [] disruptions = []
if "cancelReason" in query: if "cancelReason" in query:
disruptions.append("Cancelled (%s%s)" % (query["cancelReason"]["value"], " at " + query["cancelReason"]["_tiploc"] if query["cancelReason"]["_tiploc"] else "")) disruptions.append("Cancelled (%s%s)" % (
query["cancelReason"]["value"],
" at " + query["cancelReason"]["_tiploc"] if query["cancelReason"][
"_tiploc"] else ""))
if "delayReason" in query: if "delayReason" in query:
disruptions.append("Delayed (%s%s)" % (query["delayReason"]["value"], " at " + query["delayReason"]["_tiploc"] if query["delayReason"]["_tiploc"] else "")) disruptions.append("Delayed (%s%s)" % (
query["delayReason"]["value"],
" at " + query["delayReason"]["_tiploc"] if query["delayReason"][
"_tiploc"] else ""))
if disruptions and not external: if disruptions and not external:
disruptions = Utils.color(Utils.COLOR_RED) + ", ".join(disruptions) + Utils.color(Utils.FONT_RESET) + " " disruptions = Utils.color(Utils.COLOR_RED) + ", ".join(
disruptions) + Utils.color(Utils.FONT_RESET) + " "
elif disruptions and external: elif disruptions and external:
disruptions = ", ".join(disruptions) disruptions = ", ".join(disruptions)
else: disruptions = "" else:
disruptions = ""
stations = [] stations = []
for station in query["locations"][0] if "locations" in query else schedule["locations"]: for station in query["locations"][0] if "locations" in query else \
schedule["locations"]:
if "locations" in query: if "locations" in query:
parsed = {"name": station["locationName"], parsed = {"name": station["locationName"],
"crs": (station["crs"] if "crs" in station else station["tiploc"]).rstrip(), "crs": (
station["crs"] if "crs" in station else station[
"tiploc"]).rstrip(),
"tiploc": station["tiploc"].rstrip(), "tiploc": station["tiploc"].rstrip(),
"called": "atd" in station, "called": "atd" in station,
"passing": station["isPass"] if "isPass" in station else False, "passing": station[
"isPass"] if "isPass" in station else False,
"first": len(stations) == 0, "first": len(stations) == 0,
"last": False, "last": False,
"cancelled" : station["isCancelled"] if "isCancelled" in station else False, "cancelled": station[
"isCancelled"] if "isCancelled" in station else False,
"associations": [], "associations": [],
"length": station["length"] if "length" in station else None, "length": station[
"length"] if "length" in station else None,
"times": self.process(station), "times": self.process(station),
"platform": station["platform"] if "platform" in station else None, "platform": station[
"activity": self.activities(station["activities"]) if "activities" in station else [], "platform"] if "platform" in station else None,
"activity_p": self.reduced_activities(station["activities"]) if "activities" in station else [], "activity": self.activities(station[
"activities"]) if "activities" in station else [],
"activity_p": self.reduced_activities(station[
"activities"]) if "activities" in station else [],
} }
if parsed["cancelled"]: if parsed["cancelled"]:
parsed["times"]["arrival"].update({"short": "Cancelled", "on_time": False, "status": 2}) parsed["times"]["arrival"].update(
parsed["times"]["departure"].update({"short": "Cancelled", "on_time": False, "status": 2}) {"short": "Cancelled", "on_time": False, "status": 2})
parsed["times"]["departure"].update(
{"short": "Cancelled", "on_time": False, "status": 2})
associations = station["associations"][0] if "associations" in station else [] associations = station["associations"][
0] if "associations" in station else []
for assoc in associations: for assoc in associations:
parsed_assoc = { parsed_assoc = {
"uid_assoc": assoc.uid, "uid_assoc": assoc.uid,
"category": {"divide": "VV", "join": "JJ", "next": "NP"}[assoc["category"]], "category":
"from": parsed["first"], "direction": assoc["destTiploc"].rstrip()==parsed["tiploc"], {"divide": "VV", "join": "JJ", "next": "NP"}[
"origin_name": assoc["origin"], "origin_tiploc": assoc["originTiploc"], assoc["category"]],
"origin_crs": assoc["originCRS"] if "originCRS" in assoc else None, "from": parsed["first"],
"direction": assoc["destTiploc"].rstrip() == parsed[
"tiploc"],
"origin_name": assoc["origin"],
"origin_tiploc": assoc["originTiploc"],
"origin_crs": assoc[
"originCRS"] if "originCRS" in assoc else None,
"dest_name": assoc["destination"], "dest_tiploc": assoc["destTiploc"], "dest_name": assoc["destination"],
"dest_crs": assoc["destCRS"] if "destCRS" in assoc else None, "dest_tiploc": assoc["destTiploc"],
"dest_crs": assoc[
"destCRS"] if "destCRS" in assoc else None,
"far_name": assoc["destination"], "far_tiploc": assoc["destTiploc"], "far_name": assoc["destination"],
"far_crs": assoc["destCRS"] if "destCRS" in assoc else None, "far_tiploc": assoc["destTiploc"],
"far_crs": assoc[
"destCRS"] if "destCRS" in assoc else None,
} }
if parsed_assoc["direction"]: if parsed_assoc["direction"]:
parsed_assoc.update({"far_name": parsed_assoc["origin_name"], parsed_assoc.update(
"far_tiploc": parsed_assoc["origin_tiploc"], "far_crs": parsed_assoc["origin_crs"]}) {"far_name": parsed_assoc["origin_name"],
"far_tiploc": parsed_assoc["origin_tiploc"],
"far_crs": parsed_assoc["origin_crs"]})
parsed["associations"].append(parsed_assoc) parsed["associations"].append(parsed_assoc)
else: else:
parsed = {"name": (station["name"] or "none"), parsed = {"name": (station["name"] or "none"),
"crs": station["crs"] if station["crs"] else station["tiploc"], "crs": station["crs"] if station["crs"] else station[
"tiploc"],
"tiploc": station["tiploc"], "tiploc": station["tiploc"],
"called": False, "called": False,
"passing": bool(station.get("pass")), "passing": bool(station.get("pass")),
@ -432,47 +580,66 @@ class Module(object):
"platform": station["platform"], "platform": station["platform"],
"associations": station["associations"] or [], "associations": station["associations"] or [],
"activity": self.activities(station["activity"]), "activity": self.activities(station["activity"]),
"activity_p": self.reduced_activities(station["activity"]), "activity_p": self.reduced_activities(
station["activity"]),
} }
stations.append(parsed) stations.append(parsed)
[a for a in stations if a["called"] or a["first"]][-1]["last"] = True [a for a in stations if a["called"] or a["first"]][-1]["last"] = True
for station in stations[0:[k for k,v in enumerate(stations) if v["last"]][0]]: for station in stations[
0:[k for k, v in enumerate(stations) if v["last"]][0]]:
if not station["first"]: station["called"] = True if not station["first"]: station["called"] = True
for station in stations: for station in stations:
for assoc in station["associations"]: for assoc in station["associations"]:
assoc["summary"] = "{arrow} {assoc[category]} {assoc[uid_assoc]} {dir_arrow} {assoc[far_name]} ({code})".format(assoc=assoc, arrow=assoc["from"]*"<-" or "->", dir_arrow=(assoc["direction"])*"<-" or "->", code=assoc["far_crs"] or assoc["far_tiploc"]) assoc[
"summary"] = "{arrow} {assoc[category]} {assoc[uid_assoc]} {dir_arrow} {assoc[far_name]} ({code})".format(
assoc=assoc, arrow=assoc["from"] * "<-" or "->",
dir_arrow=(assoc["direction"]) * "<-" or "->",
code=assoc["far_crs"] or assoc["far_tiploc"])
if station["passing"]: if station["passing"]:
station["times"]["arrival"]["status"], station["times"]["departure"]["status"] = 5, 5 station["times"]["arrival"]["status"], \
station["times"]["departure"]["status"] = 5, 5
elif station["called"]: elif station["called"]:
station["times"]["arrival"]["status"], station["times"]["departure"]["status"] = 0, 0 station["times"]["arrival"]["status"], \
station["times"]["departure"]["status"] = 0, 0
station["summary"] = "%s%s (%s%s%s%s%s%s%s)%s" % ( station["summary"] = "%s%s (%s%s%s%s%s%s%s)%s" % (
"*" * station["passing"], "*" * station["passing"],
station["name"], station["name"],
station["crs"] + ", " if station["name"] != station["crs"] else '', station["crs"] + ", " if station["name"] != station[
station["length"] + " cars, " if station["length"] and (station["first"] or (station["last"]) or station["associations"]) else '', "crs"] else '',
station["length"] + " cars, " if station["length"] and (
station["first"] or (station["last"]) or station[
"associations"]) else '',
("~" if station["times"][filter["type"]]["estimate"] else '') + ("~" if station["times"][filter["type"]]["estimate"] else '') +
station["times"][filter["type"]]["prefix"].replace(filter["type"][0], ""), station["times"][filter["type"]]["prefix"].replace(
Utils.color(colours[station["times"][filter["type"]]["status"]]), filter["type"][0], ""),
Utils.color(
colours[station["times"][filter["type"]]["status"]]),
station["times"][filter["type"]]["short"], station["times"][filter["type"]]["short"],
Utils.color(Utils.FONT_RESET), Utils.color(Utils.FONT_RESET),
", "*bool(station["activity_p"]) + "+".join(station["activity_p"]), ", " * bool(station["activity_p"]) + "+".join(
station["activity_p"]),
", ".join([a["summary"] for a in station["associations"]]), ", ".join([a["summary"] for a in station["associations"]]),
) )
station["summary_external"] = "%1s%-5s %1s%-5s %-3s %-3s %-3s %s%s" % ( station[
"~"*station["times"]["a"]["estimate"] + "s"*(station["times"]["a"]["schedule"]), "summary_external"] = "%1s%-5s %1s%-5s %-3s %-3s %-3s %s%s" % (
"~" * station["times"]["a"]["estimate"] + "s" * (
station["times"]["a"]["schedule"]),
station["times"]["a"]["short"], station["times"]["a"]["short"],
"~"*station["times"]["d"]["estimate"] + "s"*(station["times"]["d"]["schedule"]), "~" * station["times"]["d"]["estimate"] + "s" * (
station["times"]["d"]["schedule"]),
station["times"]["d"]["short"], station["times"]["d"]["short"],
station["platform"] or '', station["platform"] or '',
",".join(station["activity"]) or '', ",".join(station["activity"]) or '',
station["crs"] or station["tiploc"], station["crs"] or station["tiploc"],
station["name"], station["name"],
"\n" + "\n".join([a["summary"] for a in station["associations"]]) if station["associations"] else "", "\n" + "\n".join(
[a["summary"] for a in station["associations"]]) if station[
"associations"] else "",
) )
stations_filtered = [] stations_filtered = []
@ -483,8 +650,10 @@ class Module(object):
continue continue
stations_filtered.append(station) stations_filtered.append(station)
if station["first"] and not station["last"] and filter["default"] and not external: if station["first"] and not station["last"] and filter[
stations_filtered.append({"summary": "(...)", "summary_external": "(...)"}) "default"] and not external:
stations_filtered.append(
{"summary": "(...)", "summary_external": "(...)"})
done_count = len([s for s in stations if s["called"]]) done_count = len([s for s in stations if s["called"]])
total_count = len(stations) total_count = len(stations)
@ -492,13 +661,16 @@ class Module(object):
event["stdout"].write("%s: %s\n%s%s (%s) %s %s\n\n%s" % ( event["stdout"].write("%s: %s\n%s%s (%s) %s %s\n\n%s" % (
service_id, ", ".join(sources), service_id, ", ".join(sources),
disruptions + "\n" if disruptions else '', disruptions + "\n" if disruptions else '',
query["operator"], query["operatorCode"], query["trainid"], query["serviceType"], query["operator"], query["operatorCode"], query["trainid"],
query["serviceType"],
"\n".join([s["summary_external"] for s in stations_filtered]) "\n".join([s["summary_external"] for s in stations_filtered])
)) ))
else: else:
event["stdout"].write("%s%s %s %s (%s%s%s/%s/%s): %s" % (disruptions, query["operatorCode"], event["stdout"].write("%s%s %s %s (%s%s%s/%s/%s): %s" % (
disruptions, query["operatorCode"],
query["trainid"], query["serviceType"], query["trainid"], query["serviceType"],
Utils.color(Utils.COLOR_LIGHTBLUE), done_count, Utils.color(Utils.FONT_RESET), Utils.color(Utils.COLOR_LIGHTBLUE), done_count,
Utils.color(Utils.FONT_RESET),
len(stations_filtered), total_count, len(stations_filtered), total_count,
", ".join([s["summary"] for s in stations_filtered]))) ", ".join([s["summary"] for s in stations_filtered])))
@ -506,25 +678,40 @@ class Module(object):
client = self.client client = self.client
service_id = event["args_split"][0] service_id = event["args_split"][0]
query = client.service.QueryServices(service_id, datetime.utcnow().date().isoformat(), query = client.service.QueryServices(service_id,
datetime.utcnow().time().strftime("%H:%M:%S+0000")) datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime(
"%H:%M:%S+0000"))
if not query: if not query:
return event["stderr"].write("No currently running services match this identifier") return event["stderr"].write(
"No currently running services match this identifier")
services = query["serviceList"][0] services = query["serviceList"][0]
if event.get("external"): if event.get("external"):
event["stdout"].write("\n".join(["{a.uid:6} {a.trainid:4} {a.originName} ({a.originCrs}) → {a.destinationName} ({a.destinationCrs})".format(a=a) for a in services])) event["stdout"].write("\n".join([
"{a.uid:6} {a.trainid:4} {a.originName} ({a.originCrs}) → {a.destinationName} ({a.destinationCrs})".format(
a=a) for a in services]))
else: else:
event["stdout"].write(", ".join(["h/%s r/%s u/%s rs/%s %s (%s) -> %s (%s)" % (a["trainid"], a["rid"], a["uid"], a["rsid"], a["originName"], a["originCrs"], a["destinationName"], a["destinationCrs"]) for a in services])) event["stdout"].write(", ".join([
"h/%s r/%s u/%s rs/%s %s (%s) -> %s (%s)" % (
a["trainid"], a["rid"],
a["uid"], a["rsid"],
a["originName"], a["originCrs"],
a["destinationName"],
a["destinationCrs"]) for a in
services]))
def service_code(self, event): def service_code(self, event):
client = self.client client = self.client
if not event["args"].isnumeric(): if not event["args"].isnumeric():
return event["stderr"].write("The delay/cancellation code must be a number") return event["stderr"].write(
reasons = {a["code"]:(a["lateReason"], a["cancReason"]) for a in client.service.GetReasonCodeList()[0]} "The delay/cancellation code must be a number")
reasons = {a["code"]: (a["lateReason"], a["cancReason"]) for a in
client.service.GetReasonCodeList()[0]}
if event["args"] in reasons: if event["args"] in reasons:
event["stdout"].write("%s: %s" % (event["args"], " / ".join(reasons[event["args"]]))) event["stdout"].write(
"%s: %s" % (event["args"], " / ".join(reasons[event["args"]])))
else: else:
event["stdout"].write("This doesn't seem to be a valid reason code") event["stdout"].write("This doesn't seem to be a valid reason code")

View file

@ -1,5 +1,6 @@
import EventManager import EventManager
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("numeric").on("001").hook( bot.events.on("received").on("numeric").on("001").hook(

View file

@ -4,6 +4,7 @@ import scrypt
REQUIRES_IDENTIFY = ("You need to be identified to use that command " REQUIRES_IDENTIFY = ("You need to be identified to use that command "
"(/msg %s register | /msg %s identify)") "(/msg %s register | /msg %s identify)")
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -12,13 +13,20 @@ class Module(object):
self.preprocess_command) self.preprocess_command)
bot.events.on("received").on("part").hook(self.on_part) bot.events.on("received").on("part").hook(self.on_part)
bot.events.on("received").on("command").on("identify" bot.events.on("received").on("command").on("identify"
).hook(self.identify, private_only=True, min_args=1, ).hook(self.identify,
usage="<password>", help="Identify yourself") private_only=True,
min_args=1,
usage="<password>",
help="Identify yourself")
bot.events.on("received").on("command").on("register" bot.events.on("received").on("command").on("register"
).hook(self.register, private_only=True, min_args=1, ).hook(self.register,
usage="<password>", help="Register your nickname") private_only=True,
min_args=1,
usage="<password>",
help="Register your nickname")
bot.events.on("received.command.logout").hook(self.logout, bot.events.on("received.command.logout").hook(self.logout,
private_only=True, help="Sign out from the bot") private_only=True,
help="Sign out from the bot")
bot.events.on("received.command.mypermissions").hook( bot.events.on("received.command.mypermissions").hook(
self.my_permissions, authenticated=True) self.my_permissions, authenticated=True)
@ -142,6 +150,7 @@ class Module(object):
target.set_setting("permissions", permissions) target.set_setting("permissions", permissions)
event["stdout"].write("Gave permission '%s' to %s" % ( event["stdout"].write("Gave permission '%s' to %s" % (
permission, target.nickname)) permission, target.nickname))
def remove_permission(self, event): def remove_permission(self, event):
permission = event["args_split"][1].lower() permission = event["args_split"][1].lower()
target, registered, permissions = self._get_user_details( target, registered, permissions = self._get_user_details(

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received.command.ping").hook( bot.events.on("received.command.ping").hook(

View file

@ -1,6 +1,7 @@
import datetime import datetime
import EventManager import EventManager
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -51,18 +52,23 @@ class Module(object):
self.print_line(event, "<%s> %s" % ( self.print_line(event, "<%s> %s" % (
nickname, event["message"]), nickname, event["message"]),
channel=event["channel"].name) channel=event["channel"].name)
def channel_message(self, event): def channel_message(self, event):
self._on_message(event, event["user"].nickname) self._on_message(event, event["user"].nickname)
def self_channel_message(self, event): def self_channel_message(self, event):
self._on_message(event, event["server"].nickname) self._on_message(event, event["server"].nickname)
def _on_notice(self, event, target): def _on_notice(self, event, target):
self.print_line(event, "(notice->%s) <%s> %s" % ( self.print_line(event, "(notice->%s) <%s> %s" % (
target, event["user"].nickname, event["message"])) target, event["user"].nickname, event["message"]))
def channel_notice(self, event): def channel_notice(self, event):
self._on_notice(event, event["channel"].name) self._on_notice(event, event["channel"].name)
def private_notice(self, event): def private_notice(self, event):
self._on_notice(event, event["server"].nickname) self._on_notice(event, event["server"].nickname)
def server_notice(self, event): def server_notice(self, event):
self.print_line(event, "(server notice) %s" % event["message"]) self.print_line(event, "(server notice) %s" % event["message"])
@ -70,18 +76,25 @@ class Module(object):
if not self.bot.args.verbose: if not self.bot.args.verbose:
self.print_line(event, "%s joined %s" % (nickname, self.print_line(event, "%s joined %s" % (nickname,
event["channel"].name)) event["channel"].name))
def join(self, event): def join(self, event):
self._on_join(event, event["user"].nickname) self._on_join(event, event["user"].nickname)
def self_join(self, event): def self_join(self, event):
self._on_join(event, event["server"].nickname) self._on_join(event, event["server"].nickname)
def _on_part(self, event, nickname): def _on_part(self, event, nickname):
if not self.bot.args.verbose: if not self.bot.args.verbose:
self.print_line(event, "%s left %s%s" % (nickname, self.print_line(event, "%s left %s%s" % (nickname,
event["channel"].name, "" if not event[ event["channel"].name,
"reason"] else " (%s)" % event["reason"])) "" if not event[
"reason"] else " (%s)" %
event[
"reason"]))
def part(self, event): def part(self, event):
self._on_part(event, event["user"].nickname) self._on_part(event, event["user"].nickname)
def self_part(self, event): def self_part(self, event):
self._on_part(event, event["server"].nickname) self._on_part(event, event["server"].nickname)
@ -93,24 +106,32 @@ class Module(object):
def on_quit(self, event): def on_quit(self, event):
if not self.bot.args.verbose: if not self.bot.args.verbose:
self.print_line(event, "%s quit%s" % (event["user"].nickname, self.print_line(event, "%s quit%s" % (event["user"].nickname,
"" if not event["reason"] else " (%s)" % event["reason"])) "" if not event[
"reason"] else " (%s)" %
event[
"reason"]))
def _on_kick(self, event, nickname): def _on_kick(self, event, nickname):
if not self.bot.args.verbose: if not self.bot.args.verbose:
self.print_line(event, "%s kicked %s from %s%s" % ( self.print_line(event, "%s kicked %s from %s%s" % (
event["user"].nickname, nickname, event["channel"].name, event["user"].nickname, nickname, event["channel"].name,
"" if not event["reason"] else " (%s)" % event["reason"])) "" if not event["reason"] else " (%s)" % event["reason"]))
def kick(self, event): def kick(self, event):
self._on_kick(event, event["target_user"].nickname) self._on_kick(event, event["target_user"].nickname)
def self_kick(self, event): def self_kick(self, event):
self._on_kick(event, event["server"].nickname) self._on_kick(event, event["server"].nickname)
def _on_topic(self, event, setter, action, topic, channel): def _on_topic(self, event, setter, action, topic, channel):
self.print_line(event, "topic %s by %s: %s" % (action, setter, self.print_line(event, "topic %s by %s: %s" % (action, setter,
topic), channel=channel.name) topic),
channel=channel.name)
def on_topic(self, event): def on_topic(self, event):
self._on_topic(event, event["user"].nickname, "changed", self._on_topic(event, event["user"].nickname, "changed",
event["topic"], event["channel"]) event["topic"], event["channel"])
def on_333(self, event): def on_333(self, event):
self._on_topic(event, event["setter"], "set", self._on_topic(event, event["setter"], "set",
event["channel"].topic, event["channel"]) event["channel"].topic, event["channel"])

View file

@ -54,6 +54,7 @@ QUOTES = {
"I dont need to understand how encryption works": "Amber Rudd", "I dont need to understand how encryption works": "Amber Rudd",
} }
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("get.quit-quote").hook(self.quote) bot.events.on("get.quit-quote").hook(self.quote)
@ -61,4 +62,3 @@ class Module(object):
def quote(self, event): def quote(self, event):
quote = random.choice(list(QUOTES.items())) quote = random.choice(list(QUOTES.items()))
return (" - " if quote[1] else "").join(quote) return (" - " if quote[1] else "").join(quote)

View file

@ -1,22 +1,27 @@
import random, time import random, time
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("quoteadd", bot.events.on("received").on("command").on("quoteadd",
"qadd").hook(self.quote_add, min_args=1, "qadd").hook(self.quote_add,
min_args=1,
help="Added a quote to a category", help="Added a quote to a category",
usage="<category> = <quote>") usage="<category> = <quote>")
bot.events.on("received").on("command").on("quoteget", bot.events.on("received").on("command").on("quoteget",
"qget").hook(self.quote_get, min_args=1, "qget").hook(self.quote_get,
min_args=1,
help="Find a quote within a category", help="Find a quote within a category",
usage="<category> = <search>") usage="<category> = <search>")
bot.events.on("received").on("command").on("quotedel", bot.events.on("received").on("command").on("quotedel",
"qdel").hook(self.quote_del, min_args=1, "qdel").hook(self.quote_del,
min_args=1,
help="Delete a quote from a category", help="Delete a quote from a category",
usage="<category> = <quote>") usage="<category> = <quote>")
bot.events.on("received").on("command").on("quote", bot.events.on("received").on("command").on("quote",
"q").hook(self.quote, min_args=1, "q").hook(self.quote,
min_args=1,
help="Get a random quote from a category", help="Get a random quote from a category",
usage="<category>") usage="<category>")
@ -47,7 +52,9 @@ class Module(object):
found.append(quote) found.append(quote)
if found: if found:
event["stdout"].write("%d quote%s found: %s" % (len(found), event["stdout"].write("%d quote%s found: %s" % (len(found),
"s" if len(found) > 1 else "", found[0])) "s" if len(
found) > 1 else "",
found[0]))
else: else:
event["stderr"].write("No quotes found") event["stderr"].write("No quotes found")
else: else:

View file

@ -1,13 +1,17 @@
import random, uuid import random, uuid
class Module(object): class Module(object):
_name = "Random" _name = "Random"
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("random", bot.events.on("received").on("command").on("random",
"rand").hook(self.random, help="Get a random number", "rand").hook(self.random,
help="Get a random number",
usage="[start] [end]") usage="[start] [end]")
bot.events.on("received").on("command").on("guid" bot.events.on("received").on("command").on("guid"
).hook(self.guid, help="Get a random guid") ).hook(self.guid,
help="Get a random guid")
def random(self, event): def random(self, event):
start, end = "1", "100" start, end = "1", "100"

View file

@ -1,5 +1,6 @@
import base64 import base64
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -36,4 +37,3 @@ class Module(object):
def on_90x(self, event): def on_90x(self, event):
event["server"].send_capability_end() event["server"].send_capability_end()

View file

@ -4,6 +4,7 @@ import Utils
REGEX_SPLIT = re.compile("(?<!\\\\)/") REGEX_SPLIT = re.compile("(?<!\\\\)/")
REGEX_SED = re.compile("^s/") REGEX_SED = re.compile("^s/")
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -17,7 +18,8 @@ class Module(object):
bot.events.on("postboot").on("configure").on( bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="sed-sender-only", "channelset").assure_call(setting="sed-sender-only",
help="Disable/Enable sed only looking at the messages " help="Disable/Enable sed only looking at the messages "
"sent by the user", validate=Utils.bool_or_none) "sent by the user",
validate=Utils.bool_or_none)
def channel_message(self, event): def channel_message(self, event):
sed_split = re.split(REGEX_SPLIT, event["message"], 3) sed_split = re.split(REGEX_SPLIT, event["message"], 3)
@ -59,7 +61,8 @@ class Module(object):
event, "sed-sender-only", False event, "sed-sender-only", False
) else None ) else None
line = event["channel"].buffer.find(pattern, from_self=False, line = event["channel"].buffer.find(pattern, from_self=False,
for_user=for_user, not_pattern=REGEX_SED) for_user=for_user,
not_pattern=REGEX_SED)
if line: if line:
new_message = re.sub(pattern, replace, line.message, count) new_message = re.sub(pattern, replace, line.message, count)
if line.action: if line.action:
@ -68,4 +71,6 @@ class Module(object):
prefix = "<%s>" % line.sender prefix = "<%s>" % line.sender
self.bot.events.on("send").on("stdout").call(target=event[ self.bot.events.on("send").on("stdout").call(target=event[
"channel"], module_name="Sed", server=event["server"], "channel"], module_name="Sed", server=event["server"],
message="%s %s" % (prefix, new_message)) message="%s %s" % (
prefix,
new_message))

View file

@ -1,6 +1,7 @@
import time import time
import Utils import Utils
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("message").on("channel" bot.events.on("received").on("message").on("channel"

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -8,7 +6,8 @@ class Module(object):
bot.events.on("postboot").on("configure").on("set").hook( bot.events.on("postboot").on("configure").on("set").hook(
self.postboot_set, replay=True) self.postboot_set, replay=True)
bot.events.on("postboot").on("configure").on("channelset" bot.events.on("postboot").on("configure").on("channelset"
).hook(self.postboot_channelset, replay=True) ).hook(
self.postboot_channelset, replay=True)
bot.events.on("received").on("command").on("set").hook( bot.events.on("received").on("command").on("set").hook(
self.set, help="Set a specified user setting", self.set, help="Set a specified user setting",
@ -18,17 +17,24 @@ class Module(object):
usage="<setting>", min_args=1) usage="<setting>", min_args=1)
bot.events.on("received").on("command").on("channelset" bot.events.on("received").on("command").on("channelset"
).hook(self.channel_set, channel_only=True, ).hook(self.channel_set,
channel_only=True,
help="Set a specified setting for the current channel", help="Set a specified setting for the current channel",
usage="<setting> <value>", require_mode="o") usage="<setting> <value>",
require_mode="o")
bot.events.on("received").on("command").on("channelsetoverride" bot.events.on("received").on("command").on("channelsetoverride"
).hook(self.channel_set, channel_only=True, ).hook(self.channel_set,
channel_only=True,
help="Set a specified setting for the current channel", help="Set a specified setting for the current channel",
usage="<setting> <value>", permission="channelsetoverride") usage="<setting> <value>",
permission="channelsetoverride")
bot.events.on("received").on("command").on("channelget" bot.events.on("received").on("command").on("channelget"
).hook(self.channel_get, channel_only=True, ).hook(self.channel_get,
channel_only=True,
help="Get a specified setting for the current channel", help="Get a specified setting for the current channel",
usage="<setting>", min_args=1, require_mode="o") usage="<setting>",
min_args=1,
require_mode="o")
def _postboot_set(self, settings, event): def _postboot_set(self, settings, event):
settings[event["setting"]] = {} settings[event["setting"]] = {}
@ -36,8 +42,10 @@ class Module(object):
"validate", lambda s: s) "validate", lambda s: s)
settings[event["setting"]]["help"] = event.get("help", settings[event["setting"]]["help"] = event.get("help",
"") "")
def postboot_set(self, event): def postboot_set(self, event):
self._postboot_set(self.settings, event) self._postboot_set(self.settings, event)
def postboot_channelset(self, event): def postboot_channelset(self, event):
self._postboot_set(self.channel_settings, event) self._postboot_set(self.channel_settings, event)
@ -59,6 +67,7 @@ class Module(object):
else: else:
event["stdout"].write("Available settings: %s" % ( event["stdout"].write("Available settings: %s" % (
", ".join(settings.keys()))) ", ".join(settings.keys())))
def set(self, event): def set(self, event):
self._set(self.settings, event, event["user"]) self._set(self.settings, event, event["user"])

View file

@ -1,5 +1,6 @@
import signal import signal
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -8,7 +9,8 @@ class Module(object):
def SIGINT(self, signum, frame): def SIGINT(self, signum, frame):
print() print()
self.bot.events.on("signal").on("interrupt").call(signum=signum, frame=frame) self.bot.events.on("signal").on("interrupt").call(signum=signum,
frame=frame)
for server in self.bot.servers.values(): for server in self.bot.servers.values():
reason = "Leaving" reason = "Leaving"

View file

@ -7,12 +7,15 @@ URL_SOUNDCLOUD_TRACK = "http://api.soundcloud.com/tracks"
URL_SOUNDCLOUD_RESOLVE = "http://api.soundcloud.com/resolve" URL_SOUNDCLOUD_RESOLVE = "http://api.soundcloud.com/resolve"
REGEX_SOUNDCLOUD = "https?://soundcloud.com/([^/]+)/([^/]+)" REGEX_SOUNDCLOUD = "https?://soundcloud.com/([^/]+)/([^/]+)"
class Module(object): class Module(object):
_name = "SoundCloud" _name = "SoundCloud"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("soundcloud", "sc" bot.events.on("received").on("command").on("soundcloud", "sc"
).hook(self.soundcloud, help="Search SoundCloud") ).hook(self.soundcloud,
help="Search SoundCloud")
def soundcloud(self, event): def soundcloud(self, event):
query = None query = None
@ -56,6 +59,7 @@ class Module(object):
duration = duration[3:] duration = duration[3:]
link = page["permalink_url"] link = page["permalink_url"]
event["stdout"].write("%s [%s] (posted by %s) %s" % (title, event["stdout"].write("%s [%s] (posted by %s) %s" % (title,
duration, user, link)) duration, user,
link))
else: else:
event["stderr"].write("Failed to load results") event["stderr"].write("Failed to load results")

View file

@ -3,6 +3,7 @@ import Utils
URL_SPOTIFY = "https://api.spotify.com/v1/search" URL_SPOTIFY = "https://api.spotify.com/v1/search"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("spotify").hook( bot.events.on("received").on("command").on("spotify").hook(
@ -11,7 +12,9 @@ class Module(object):
def spotify(self, event): def spotify(self, event):
page = Utils.get_url(URL_SPOTIFY, get_params={"type": "track", page = Utils.get_url(URL_SPOTIFY, get_params={"type": "track",
"limit": 1, "q": event["args"]}, json=True) "limit": 1,
"q": event["args"]},
json=True)
if page: if page:
if len(page["tracks"]["items"]): if len(page["tracks"]["items"]):
item = page["tracks"]["items"][0] item = page["tracks"]["items"][0]

View file

@ -1,14 +1,17 @@
import time import time
import Utils import Utils
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.boot_time = time.time() self.boot_time = time.time()
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("uptime" bot.events.on("received").on("command").on("uptime"
).hook(self.uptime, help="Show my uptime") ).hook(self.uptime,
help="Show my uptime")
bot.events.on("received").on("command").on("stats" bot.events.on("received").on("command").on("stats"
).hook(self.stats, help="Show my network/channel/user stats") ).hook(self.stats,
help="Show my network/channel/user stats")
def uptime(self, event): def uptime(self, event):
seconds = int(time.time() - self.boot_time) seconds = int(time.time() - self.boot_time)
@ -23,7 +26,6 @@ class Module(object):
channels += len(server.channels) channels += len(server.channels)
users += len(server.users) users += len(server.users)
response = "I currently have %d network" % networks response = "I currently have %d network" % networks
if networks > 1: if networks > 1:
response += "s" response += "s"

View file

@ -4,41 +4,64 @@ import random
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received.command.strax").hook( bot.events.on("received.command.strax").hook(
self.strax, help="Suggests a glorious method of battle for the glory of the Sontaran Empire, through IRC!") self.strax,
help="Suggests a glorious method of battle for the glory of the Sontaran Empire, through IRC!")
def strax(self, event): def strax(self, event):
suggestion_greeting = ["Might I suggest", "Can I suggest", "Should we attack immediately with"] suggestion_greeting = ["Might I suggest", "Can I suggest",
command_greeting = ["We should attack now with", "We must attack now with", "I suggest attacking with", "Should we attack immediately with"]
command_greeting = ["We should attack now with",
"We must attack now with",
"I suggest attacking with",
"We should coordinate an attack with"] "We should coordinate an attack with"]
method_of_attack_a = ["full-frontal", "pincer", "surprise", "brutally excessive", "multi-pronged", "glorious", method_of_attack_a = ["full-frontal", "pincer", "surprise",
"violent", "devastating", "superior", "fast-paced", "fleet-wide", "stealth", "brutally excessive", "multi-pronged", "glorious",
"diversionary", "exceptional", "point-blank", "night time"] "violent", "devastating", "superior",
method_of_attack_an = ["acid-heavy", "immediate", "overwhelming", "unstoppable", "underground", "arial", "fast-paced", "fleet-wide", "stealth",
"diversionary", "exceptional", "point-blank",
"night time"]
method_of_attack_an = ["acid-heavy", "immediate", "overwhelming",
"unstoppable", "underground", "arial",
"naval", "amphibious", "full-scale"] "naval", "amphibious", "full-scale"]
type_of_attack = ["assault", "attack", "bombardment", "offensive", "barrage", "charge", "strike", "operation", type_of_attack = ["assault", "attack", "bombardment", "offensive",
"barrage", "charge", "strike", "operation",
"manoeuvre", "blitzkrieg", "ambush", "massacre"] "manoeuvre", "blitzkrieg", "ambush", "massacre"]
attack_adjective = ["laser", "berserker", "acid", "armoured attack", "proton", attack_adjective = ["laser", "berserker", "acid", "armoured attack",
"proton",
"three kinds of", "atomic", "toxic", "explosive", "three kinds of", "atomic", "toxic", "explosive",
"red-hot", "thermal", "automated fire", "cluster", "red-hot", "thermal", "automated fire", "cluster",
"enhanced germ", "energy-drink-fueled", "battle ready", "Sontaran", "military"] "enhanced germ", "energy-drink-fueled",
attack_object = ["bees", "chainsaws", "marmots", "acid", "monkeys", "mines", "bombs", "snakes", "spiders", "battle ready", "Sontaran", "military"]
"knives", "rockets", "sharks", "owls", "repurposed cybermats", "cannons", "alligators", "ants", attack_object = ["bees", "chainsaws", "marmots", "acid", "monkeys",
"gorillas", "genetically enhanced cyber-elephants", "mechanoids", "KGB agents", "mines", "bombs", "snakes", "spiders",
"knives", "rockets", "sharks", "owls",
"repurposed cybermats", "cannons", "alligators",
"ants",
"gorillas", "genetically enhanced cyber-elephants",
"mechanoids", "KGB agents",
"MI5 operatives", "thermonuclear missiles"] "MI5 operatives", "thermonuclear missiles"]
attack_object_two = ["robots", "ninjas", "grenades", "a dolphin full of napalm", "dynamite", attack_object_two = ["robots", "ninjas", "grenades",
"xenomorphs", "lots and lots of C4", "tactical nukes", "bio-weapons", "a dolphin full of napalm", "dynamite",
"rocket launchers", "an elephant", "a memory worm for afterwards", "this pencil"] "xenomorphs", "lots and lots of C4",
"tactical nukes", "bio-weapons",
"rocket launchers", "an elephant",
"a memory worm for afterwards", "this pencil"]
method_of_attack = " an " + random.choice(method_of_attack_an) if random.choice([1, method_of_attack = " an " + random.choice(
method_of_attack_an) if random.choice([1,
2]) == 1 else " a " + random.choice( 2]) == 1 else " a " + random.choice(
method_of_attack_a) method_of_attack_a)
greeting_choice = random.choice([1, 2]) greeting_choice = random.choice([1, 2])
greeting = random.choice(suggestion_greeting) if greeting_choice == 1 else random.choice(command_greeting) greeting = random.choice(
suggestion_greeting) if greeting_choice == 1 else random.choice(
command_greeting)
exclamation = "?" if greeting_choice == 1 else "!" exclamation = "?" if greeting_choice == 1 else "!"
suggestion = greeting + method_of_attack + " " + random.choice(type_of_attack) + " with " + random.choice( suggestion = greeting + method_of_attack + " " + random.choice(
attack_adjective) + " " + random.choice(attack_object) + " and " + random.choice( type_of_attack) + " with " + random.choice(
attack_adjective) + " " + random.choice(
attack_object) + " and " + random.choice(
attack_object_two) + exclamation attack_object_two) + exclamation
event["stdout"].write(suggestion) event["stdout"].write(suggestion)

View file

@ -5,6 +5,7 @@ import json
from datetime import datetime from datetime import datetime
from threading import Thread from threading import Thread
class Module(Thread): class Module(Thread):
_name = "telegram" _name = "telegram"
@ -26,7 +27,8 @@ class Module(Thread):
dolphin.events.on("signal").on("interrupt").hook(self.sigint) dolphin.events.on("signal").on("interrupt").hook(self.sigint)
def start(self, bot, update): def start(self, bot, update):
bot.send_message(chat_id=update.message.chat_id, text="`Dolphin, but Telegram`", parse_mode="Markdown") bot.send_message(chat_id=update.message.chat_id,
text="`Dolphin, but Telegram`", parse_mode="Markdown")
def handle(self, bot, update): def handle(self, bot, update):
message, text = update.message, update.message.text message, text = update.message, update.message.text
@ -45,18 +47,23 @@ class Module(Thread):
"stderr": IOWrapper(bot, message.chat_id, message.message_id), "stderr": IOWrapper(bot, message.chat_id, message.message_id),
"external": True, "external": True,
} }
self.dolphin.events.on("telegram").on("command").on(command).call(**data) self.dolphin.events.on("telegram").on("command").on(command).call(
**data)
def sigint(self, event): def sigint(self, event):
self.updater.stop() self.updater.stop()
class IOWrapper: class IOWrapper:
def __init__(self, bot, chat_id, message_id): def __init__(self, bot, chat_id, message_id):
self.bot = bot self.bot = bot
self.chat_id = chat_id self.chat_id = chat_id
self.message_id = message_id self.message_id = message_id
def write(self, text): def write(self, text):
if len(text) > 4096 - 10: if len(text) > 4096 - 10:
text = text[:4086] + "" text = text[:4086] + ""
self.bot.send_message(chat_id=self.chat_id, text="```\n" + text + "\n```", self.bot.send_message(chat_id=self.chat_id,
reply_to_message_id=self.message_id, parse_mode="Markdown") text="```\n" + text + "\n```",
reply_to_message_id=self.message_id,
parse_mode="Markdown")

View file

@ -7,7 +7,9 @@ URL_BUS_SEARCH = "https://api.tfl.gov.uk/StopPoint/Search/%s"
URL_LINE_ARRIVALS = "https://api.tfl.gov.uk/Line/%s/Arrivals" URL_LINE_ARRIVALS = "https://api.tfl.gov.uk/Line/%s/Arrivals"
URL_LINE = "https://api.tfl.gov.uk/Line/Mode/tube/Status" URL_LINE = "https://api.tfl.gov.uk/Line/Mode/tube/Status"
LINE_NAMES = ["bakerloo", "central", "circle", "district", "hammersmith and city", "jubilee", "metropolitan", "piccadilly", "victoria", "waterloo and city"] LINE_NAMES = ["bakerloo", "central", "circle", "district",
"hammersmith and city", "jubilee", "metropolitan", "piccadilly",
"victoria", "waterloo and city"]
URL_STOP = "https://api.tfl.gov.uk/StopPoint/%s" URL_STOP = "https://api.tfl.gov.uk/StopPoint/%s"
URL_STOP_SEARCH = "https://api.tfl.gov.uk/StopPoint/Search/%s" URL_STOP_SEARCH = "https://api.tfl.gov.uk/StopPoint/Search/%s"
@ -16,10 +18,13 @@ URL_VEHICLE = "https://api.tfl.gov.uk/Vehicle/%s/Arrivals"
URL_ROUTE = "https://api.tfl.gov.uk/Line/%s/Route/Sequence/all?excludeCrowding=True" URL_ROUTE = "https://api.tfl.gov.uk/Line/%s/Route/Sequence/all?excludeCrowding=True"
PLATFORM_TYPES = ["Northbound", "Southbound", "Eastbound", "Westbound", "Inner Rail", "Outer Rail"] PLATFORM_TYPES = ["Northbound", "Southbound", "Eastbound", "Westbound",
"Inner Rail", "Outer Rail"]
class Module(object): class Module(object):
_name = "TFL" _name = "TFL"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
self.result_map = {} self.result_map = {}
@ -32,11 +37,13 @@ class Module(object):
help="Get line status for TfL underground lines", help="Get line status for TfL underground lines",
usage="<line_name>") usage="<line_name>")
bot.events.on("received").on("command").on("tflsearch" bot.events.on("received").on("command").on("tflsearch"
).hook(self.search, min_args=1, ).hook(self.search,
min_args=1,
help="Get a list of TfL stop IDs for a given name", help="Get a list of TfL stop IDs for a given name",
usage="<name>") usage="<name>")
bot.events.on("received").on("command").on("tflvehicle" bot.events.on("received").on("command").on("tflvehicle"
).hook(self.vehicle, min_args=1, ).hook(self.vehicle,
min_args=1,
help="Get information for a given vehicle", help="Get information for a given vehicle",
usage="<ID>") usage="<ID>")
bot.events.on("received").on("command").on("tflstop" bot.events.on("received").on("command").on("tflstop"
@ -44,7 +51,8 @@ class Module(object):
help="Get information for a given stop", help="Get information for a given stop",
usage="<stop_id>") usage="<stop_id>")
bot.events.on("received").on("command").on("tflservice" bot.events.on("received").on("command").on("tflservice"
).hook(self.service, min_args=1, ).hook(self.service,
min_args=1,
help="Get service information and arrival estimates", help="Get service information and arrival estimates",
usage="<service index>") usage="<service index>")
@ -57,11 +65,15 @@ class Module(object):
time_until = vehicle_due - datetime.datetime.utcnow() time_until = vehicle_due - datetime.datetime.utcnow()
time_until = int(time_until.total_seconds() / 60) time_until = int(time_until.total_seconds() / 60)
if time_until == 0: human_time = "due" if time_until == 0:
else: human_time = "in %s min" % time_until human_time = "due"
else:
human_time = "in %s min" % time_until
if human: return human_time if human:
else: return time_until return human_time
else:
return time_until
def platform(self, platform, short=False): def platform(self, platform, short=False):
p = re.compile("(?:(.*) - Platform (\\d+)|(.*bound) Platform (\\d+))") p = re.compile("(?:(.*) - Platform (\\d+)|(.*bound) Platform (\\d+))")
@ -103,16 +115,23 @@ class Module(object):
for bus in bus_stop: for bus in bus_stop:
bus_number = bus["lineName"] bus_number = bus["lineName"]
human_time = self.vehicle_span(bus["expectedArrival"]) human_time = self.vehicle_span(bus["expectedArrival"])
time_until = self.vehicle_span(bus["expectedArrival"], human=False) time_until = self.vehicle_span(bus["expectedArrival"],
human=False)
# If the mode is "tube", "Underground Station" is redundant # If the mode is "tube", "Underground Station" is redundant
destination = bus.get("destinationName", "?") destination = bus.get("destinationName", "?")
if (bus["modeName"] == "tube"): destination = destination.replace(" Underground Station", "") if (bus[
"modeName"] == "tube"): destination = destination.replace(
" Underground Station", "")
busses.append({"route": bus_number, "time": time_until, "id": bus["vehicleId"], busses.append({"route": bus_number, "time": time_until,
"destination": destination, "human_time": human_time, "mode": bus["modeName"], "id": bus["vehicleId"],
"destination": destination,
"human_time": human_time,
"mode": bus["modeName"],
"platform": bus["platformName"], "platform": bus["platformName"],
"platform_short" : self.platform(bus["platformName"], short=True)}) "platform_short": self.platform(
bus["platformName"], short=True)})
if busses: if busses:
busses = sorted(busses, key=lambda b: b["time"]) busses = sorted(busses, key=lambda b: b["time"])
busses_filtered = [] busses_filtered = []
@ -122,11 +141,14 @@ class Module(object):
# dedup if target route isn't "*", filter if target route isn't None or "*" # dedup if target route isn't "*", filter if target route isn't None or "*"
for b in busses: for b in busses:
if target_bus_route != "*": if target_bus_route != "*":
if (b["route"], b["destination"]) in bus_route_dest: continue if (b["route"],
if bus_route_plat.count((b["route"], b["platform"])) >= 2: continue b["destination"]) in bus_route_dest: continue
if bus_route_plat.count(
(b["route"], b["platform"])) >= 2: continue
bus_route_plat.append((b["route"], b["platform"])) bus_route_plat.append((b["route"], b["platform"]))
bus_route_dest.append((b["route"], b["destination"])) bus_route_dest.append((b["route"], b["destination"]))
if b["route"] == target_bus_route or not target_bus_route: if b[
"route"] == target_bus_route or not target_bus_route:
busses_filtered.append(b) busses_filtered.append(b)
else: else:
busses_filtered.append(b) busses_filtered.append(b)
@ -134,7 +156,8 @@ class Module(object):
self.result_map[event["target"].id] = busses_filtered self.result_map[event["target"].id] = busses_filtered
# do the magic formatty things! # do the magic formatty things!
busses_string = ", ".join(["%s (%s, %s)" % (b["destination"], b["route"], b["human_time"], busses_string = ", ".join(["%s (%s, %s)" % (
b["destination"], b["route"], b["human_time"],
) for b in busses_filtered]) ) for b in busses_filtered])
event["stdout"].write("%s (%s): %s" % (stop_name, stop_id, event["stdout"].write("%s (%s): %s" % (stop_name, stop_id,
@ -177,7 +200,9 @@ class Module(object):
for status in statuses: for status in statuses:
for arg in event["args_split"]: for arg in event["args_split"]:
if arg.lower() in status["name"].lower(): if arg.lower() in status["name"].lower():
result += "%s: %s (%d) '%s'; " % (status["name"], status["description"], status["severity"], status["reason"]) result += "%s: %s (%d) '%s'; " % (
status["name"], status["description"],
status["severity"], status["reason"])
if result: if result:
event["stdout"].write(result[:-2]) event["stdout"].write(result[:-2])
else: else:
@ -191,12 +216,16 @@ class Module(object):
stop_name = event["args"].replace(" ", "%20") stop_name = event["args"].replace(" ", "%20")
stop_search = Utils.get_url(URL_STOP_SEARCH % stop_name, get_params={ stop_search = Utils.get_url(URL_STOP_SEARCH % stop_name, get_params={
"app_id": app_id, "app_key": app_key, "maxResults": "6", "faresOnly": "False"}, json=True) "app_id": app_id, "app_key": app_key, "maxResults": "6",
"faresOnly": "False"}, json=True)
if stop_search: if stop_search:
for stop in stop_search["matches"]: for stop in stop_search["matches"]:
pass pass
results = ["%s (%s): %s" % (stop["name"], ", ".join(stop["modes"]), stop["id"]) for stop in stop_search["matches"]] results = ["%s (%s): %s" % (
event["stdout"].write("[%s results] %s" % (stop_search["total"], "; ".join(results))) stop["name"], ", ".join(stop["modes"]), stop["id"]) for stop in
stop_search["matches"]]
event["stdout"].write(
"[%s results] %s" % (stop_search["total"], "; ".join(results)))
else: else:
event["stderr"].write("No results") event["stderr"].write("No results")
@ -209,12 +238,16 @@ class Module(object):
vehicle = Utils.get_url(URL_VEHICLE % vehicle_id, get_params={ vehicle = Utils.get_url(URL_VEHICLE % vehicle_id, get_params={
"app_id": app_id, "app_key": app_key}, json=True)[0] "app_id": app_id, "app_key": app_key}, json=True)[0]
arrival_time = self.vehicle_span(vehicle["expectedArrival"], human=False) arrival_time = self.vehicle_span(vehicle["expectedArrival"],
human=False)
platform = self.platform(vehicle["platformName"]) platform = self.platform(vehicle["platformName"])
event["stdout"].write("%s (%s) to %s. %s. Arrival at %s (%s) in %s minutes on %s" % ( event["stdout"].write(
vehicle["vehicleId"], vehicle["lineName"], vehicle["destinationName"], vehicle["currentLocation"], "%s (%s) to %s. %s. Arrival at %s (%s) in %s minutes on %s" % (
vehicle["stationName"], vehicle["naptanId"], arrival_time, platform)) vehicle["vehicleId"], vehicle["lineName"],
vehicle["destinationName"], vehicle["currentLocation"],
vehicle["stationName"], vehicle["naptanId"], arrival_time,
platform))
def service(self, event): def service(self, event):
app_id = self.bot.config["tfl-api-id"] app_id = self.bot.config["tfl-api-id"]
@ -228,19 +261,25 @@ class Module(object):
return return
results = self.result_map[event["target"].id] results = self.result_map[event["target"].id]
if int(service_id) >= len(results): if int(service_id) >= len(results):
event["stdout"].write("%s is too high. Remember that the first arrival is 0" % service_id) event["stdout"].write(
"%s is too high. Remember that the first arrival is 0" % service_id)
return return
service = results[int(service_id)] service = results[int(service_id)]
arrivals = Utils.get_url(URL_LINE_ARRIVALS % service["route"], get_params={ arrivals = Utils.get_url(URL_LINE_ARRIVALS % service["route"],
"app_id": app_id, "app_key": app_key}, json=True) get_params={
"app_id": app_id, "app_key": app_key},
json=True)
arrivals = [a for a in arrivals if a["vehicleId"] == service["id"]] arrivals = [a for a in arrivals if a["vehicleId"] == service["id"]]
arrivals = sorted(arrivals, key=lambda b: b["timeToStation"]) arrivals = sorted(arrivals, key=lambda b: b["timeToStation"])
event["stdout"].write( event["stdout"].write(
"%s (%s) to %s: " % (arrivals[0]["vehicleId"], arrivals[0]["lineName"], arrivals[0]["destinationName"]) + "%s (%s) to %s: " % (
arrivals[0]["vehicleId"], arrivals[0]["lineName"],
arrivals[0]["destinationName"]) +
", ".join(["%s (%s, %s)" % ", ".join(["%s (%s, %s)" %
(a["stationName"], self.platform(a.get("platformName", "?"), True), (a["stationName"],
self.platform(a.get("platformName", "?"), True),
a["expectedArrival"][11:16] a["expectedArrival"][11:16]
) for a in arrivals])) ) for a in arrivals]))

View file

@ -4,18 +4,21 @@ import Utils
URL_THESAURUS = "http://words.bighugelabs.com/api/2/%s/%s/json" URL_THESAURUS = "http://words.bighugelabs.com/api/2/%s/%s/json"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("synonym", bot.events.on("received").on("command").on("synonym",
"antonym").hook(self.thesaurus, min_args=1, "antonym").hook(
self.thesaurus, min_args=1,
help="Get synonyms/antonyms for a provided phrase", help="Get synonyms/antonyms for a provided phrase",
usage="<word> [type]") usage="<word> [type]")
def thesaurus(self, event): def thesaurus(self, event):
phrase = event["args_split"][0] phrase = event["args_split"][0]
page = Utils.get_url(URL_THESAURUS % (self.bot.config[ page = Utils.get_url(URL_THESAURUS % (self.bot.config[
"bighugethesaurus-api-key"], phrase), json=True) "bighugethesaurus-api-key"],
phrase), json=True)
syn_ant = event["command"][:3] syn_ant = event["command"][:3]
if page: if page:
if not len(event["args_split"]) > 1: if not len(event["args_split"]) > 1:

View file

@ -3,6 +3,7 @@ import Utils
REGEX_URL = re.compile("https?://\S+", re.I) REGEX_URL = re.compile("https?://\S+", re.I)
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("title", "t").hook( bot.events.on("received").on("command").on("title", "t").hook(
@ -27,7 +28,8 @@ class Module(object):
title = soup.title title = soup.title
if title: if title:
title = title.text.replace("\n", " ").replace("\r", "" title = title.text.replace("\n", " ").replace("\r", ""
).replace(" ", " ").strip() ).replace(" ",
" ").strip()
event["stdout"].write(title) event["stdout"].write(title)
else: else:
event["stderr"].write("No title found.") event["stderr"].write("No title found.")

View file

@ -1,5 +1,6 @@
import EventManager import EventManager
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("message").on("channel" bot.events.on("received").on("message").on("channel"

View file

@ -1,5 +1,3 @@
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -16,17 +14,21 @@ class Module(object):
def todo(self, event): def todo(self, event):
todo = event["user"].get_setting("todo", []) todo = event["user"].get_setting("todo", [])
if event["args"]: if event["args"]:
if event["args_split"][0].isdigit() and int(event["args_split"][0]) > 0: if event["args_split"][0].isdigit() and int(
event["args_split"][0]) > 0:
index = int(event["args_split"][0]) index = int(event["args_split"][0])
if len(todo) >= index: if len(todo) >= index:
event["stdout"].write("Todo %d: %s" % (index, todo[index-1])) event["stdout"].write(
"Todo %d: %s" % (index, todo[index - 1]))
else: else:
event["stderr"].write("You do not have that many things in your todo") event["stderr"].write(
"You do not have that many things in your todo")
else: else:
event["stderr"].write("Please provide a number") event["stderr"].write("Please provide a number")
else: else:
todo_count = len(todo) todo_count = len(todo)
event["stdout"].write("There are %d items in your todo" % todo_count) event["stdout"].write(
"There are %d items in your todo" % todo_count)
def todo_add(self, event): def todo_add(self, event):
arg_lower = event["args"].lower() arg_lower = event["args"].lower()
@ -52,4 +54,5 @@ class Module(object):
event["stderr"].write("You do not have that many things in " event["stderr"].write("You do not have that many things in "
"your todo") "your todo")
else: else:
event["stderr"].write("Please provided a todo item number to remove") event["stderr"].write(
"Please provided a todo item number to remove")

View file

@ -5,16 +5,19 @@ import Utils
URL_TRAKT = "https://api-v2launch.trakt.tv/users/%s/watching" URL_TRAKT = "https://api-v2launch.trakt.tv/users/%s/watching"
URL_TRAKTSLUG = "https://trakt.tv/%s/%s" URL_TRAKTSLUG = "https://trakt.tv/%s/%s"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("nowwatching", bot.events.on("received").on("command").on("nowwatching",
"nw").hook(self.now_watching, "nw").hook(self.now_watching,
help="Get what you or another user is now watching " help="Get what you or another user is now watching "
"on trakt.tv", usage="[username]") "on trakt.tv",
usage="[username]")
bot.events.on("postboot").on("configure").on("set" bot.events.on("postboot").on("configure").on("set"
).assure_call(setting="trakt", help="Set username on trakt.tv") ).assure_call(
setting="trakt", help="Set username on trakt.tv")
def now_watching(self, event): def now_watching(self, event):
if event["args"]: if event["args"]:

View file

@ -5,6 +5,7 @@ URL_TRANSLATE = "http://translate.googleapis.com/translate_a/single"
URL_LANGUAGES = "https://cloud.google.com/translate/docs/languages" URL_LANGUAGES = "https://cloud.google.com/translate/docs/languages"
REGEX_LANGUAGES = re.compile("(\w+)?:(\w+)? ") REGEX_LANGUAGES = re.compile("(\w+)?:(\w+)? ")
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("translate", "tr").hook( bot.events.on("received").on("command").on("translate", "tr").hook(
@ -47,4 +48,3 @@ class Module(object):
else: else:
event["stderr"].write("Failed to translate, try checking " event["stderr"].write("Failed to translate, try checking "
"source/target languages (" + URL_LANGUAGES + ")") "source/target languages (" + URL_LANGUAGES + ")")

View file

@ -10,11 +10,13 @@ import Utils
REGEX_TWITTERURL = re.compile( REGEX_TWITTERURL = re.compile(
"https?://(?:www\.)?twitter.com/[^/]+/status/(\d+)", re.I) "https?://(?:www\.)?twitter.com/[^/]+/status/(\d+)", re.I)
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("twitter", "tw" bot.events.on("received").on("command").on("twitter", "tw"
).hook(self.twitter, help="Find a tweet", ).hook(self.twitter,
help="Find a tweet",
usage="[@username/URL/ID]") usage="[@username/URL/ID]")
def make_timestamp(self, s): def make_timestamp(self, s):
@ -64,13 +66,17 @@ class Module(object):
retweet_timestamp = self.make_timestamp(tweet[ retweet_timestamp = self.make_timestamp(tweet[
"created_at"]) "created_at"])
original_timestamp = self.make_timestamp(tweet[ original_timestamp = self.make_timestamp(tweet[
"retweeted_status"]["created_at"]) "retweeted_status"][
"created_at"])
event["stdout"].write("(%s (%s) retweeted %s (%s)) %s" % ( event["stdout"].write("(%s (%s) retweeted %s (%s)) %s" % (
username, retweet_timestamp, username, retweet_timestamp,
original_username, original_timestamp, original_text)) original_username, original_timestamp, original_text))
else: else:
event["stdout"].write("(%s, %s) %s" % (username, event["stdout"].write("(%s, %s) %s" % (username,
self.make_timestamp(tweet["created_at"]), tweet["text"])) self.make_timestamp(
tweet[
"created_at"]),
tweet["text"]))
else: else:
event["stderr"].write("Invalid tweet identifiers provided") event["stderr"].write("Invalid tweet identifiers provided")
else: else:

View file

@ -2,8 +2,10 @@ import Utils
UPCITEMDB_URL = "https://api.upcitemdb.com/prod/trial/lookup" UPCITEMDB_URL = "https://api.upcitemdb.com/prod/trial/lookup"
class Module(object): class Module(object):
_name = "UPC" _name = "UPC"
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on( bot.events.on("received").on("command").on(
@ -48,6 +50,7 @@ class Module(object):
event["stdout"].write("%s%s%s(weight: %s" event["stdout"].write("%s%s%s(weight: %s"
", size: %s, price: %s)" % ( ", size: %s, price: %s)" % (
brand, title, description, weight, size, pricing)) brand, title, description, weight, size,
pricing))
else: else:
event["stderr"].write("Failed to load results") event["stderr"].write("Failed to load results")

View file

@ -4,6 +4,7 @@ import Utils
URL_URBANDICTIONARY = "http://api.urbandictionary.com/v0/define" URL_URBANDICTIONARY = "http://api.urbandictionary.com/v0/define"
REGEX_DEFNUMBER = re.compile("-n(\d+) \S+") REGEX_DEFNUMBER = re.compile("-n(\d+) \S+")
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("urbandictionary", "ud" bot.events.on("received").on("command").on("urbandictionary", "ud"
@ -25,8 +26,11 @@ class Module(object):
if number > 0 and len(page["list"]) > number - 1: if number > 0 and len(page["list"]) > number - 1:
definition = page["list"][number - 1] definition = page["list"][number - 1]
event["stdout"].write("%s: %s" % (definition["word"], event["stdout"].write("%s: %s" % (definition["word"],
definition["definition"].replace("\n", " ").replace( definition[
"\r", "").replace(" ", " "))) "definition"].replace(
"\n", " ").replace(
"\r", "").replace(
" ", " ")))
else: else:
event["stderr"].write("Definition number does not exist") event["stderr"].write("Definition number does not exist")
else: else:

View file

@ -4,6 +4,7 @@ import Utils
URL_WEATHER = "http://api.openweathermap.org/data/2.5/weather" URL_WEATHER = "http://api.openweathermap.org/data/2.5/weather"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -33,6 +34,7 @@ class Module(object):
location, celsius, fahrenheit, description, humidity, location, celsius, fahrenheit, description, humidity,
wind_speed)) wind_speed))
else: else:
event["stderr"].write("No weather information for this location") event["stderr"].write(
"No weather information for this location")
else: else:
event["stderr"].write("Failed to load results") event["stderr"].write("Failed to load results")

View file

@ -2,11 +2,13 @@ import Utils
URL_WIKIPEDIA = "https://en.wikipedia.org/w/api.php" URL_WIKIPEDIA = "https://en.wikipedia.org/w/api.php"
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("wiki", "wi" bot.events.on("received").on("command").on("wiki", "wi"
).hook(self.wikipedia, min_args=1) ).hook(self.wikipedia,
min_args=1)
def wikipedia(self, event): def wikipedia(self, event):
page = Utils.get_url(URL_WIKIPEDIA, get_params={ page = Utils.get_url(URL_WIKIPEDIA, get_params={
@ -25,4 +27,3 @@ class Module(object):
event["stderr"].write("No results found") event["stderr"].write("No results found")
else: else:
event["stderr"].write("Failed to load results") event["stderr"].write("Failed to load results")

View file

@ -6,19 +6,25 @@ import Utils
URL_WA = "http://api.wolframalpha.com/v2/query" URL_WA = "http://api.wolframalpha.com/v2/query"
REGEX_CHARHEX = re.compile("\\\\:(\S{4})") REGEX_CHARHEX = re.compile("\\\\:(\S{4})")
class Module(object): class Module(object):
_name = "Wolfram|Alpha" _name = "Wolfram|Alpha"
def __init__(self, bot): def __init__(self, bot):
bot.events.on("received").on("command").on("wolframalpha", "wa" bot.events.on("received").on("command").on("wolframalpha", "wa"
).hook(self.wa, min_args=1, help= ).hook(self.wa, min_args=1,
help=
"Evauate a given string on Wolfram|Alpha", "Evauate a given string on Wolfram|Alpha",
usage="<query>") usage="<query>")
self.bot = bot self.bot = bot
def wa(self, event): def wa(self, event):
soup = Utils.get_url(URL_WA, get_params={"input": event["args"], soup = Utils.get_url(URL_WA, get_params={"input": event["args"],
"appid": self.bot.config["wolframalpha-api-key"], "appid": self.bot.config[
"format": "plaintext", "reinterpret": "true"}, soup=True) "wolframalpha-api-key"],
"format": "plaintext",
"reinterpret": "true"},
soup=True)
if soup: if soup:
if int(soup.find("queryresult").get("numpods")) > 0: if int(soup.find("queryresult").get("numpods")) > 0:
@ -29,8 +35,10 @@ class Module(object):
if pod.get("primary") == "true": if pod.get("primary") == "true":
answer = pod.find("subpod").find("plaintext") answer = pod.find("subpod").find("plaintext")
text = "(%s) %s" % (input.replace(" | ", ": "), text = "(%s) %s" % (input.replace(" | ", ": "),
answer.text.strip().replace(" | ", ": " answer.text.strip().replace(" | ",
).replace("\n", " | ").replace("\r", "")) ": "
).replace(
"\n", " | ").replace("\r", ""))
while True: while True:
match = re.search(REGEX_CHARHEX, text) match = re.search(REGEX_CHARHEX, text)
if match: if match:

View file

@ -1,6 +1,7 @@
import time import time
import Utils import Utils
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
@ -9,15 +10,20 @@ class Module(object):
bot.events.on("self").on("message").on("channel" bot.events.on("self").on("message").on("channel"
).hook(self.self_channel_message) ).hook(self.self_channel_message)
bot.events.on("received").on("command").on("words" bot.events.on("received").on("command").on("words"
).hook(self.words, channel_only=True, ).hook(self.words,
usage="<nickname>", help= channel_only=True,
usage="<nickname>",
help=
"See how many words you or the given nickname have used") "See how many words you or the given nickname have used")
bot.events.on("received").on("command").on("trackword" bot.events.on("received").on("command").on("trackword"
).hook(self.track_word, min_args=1, ).hook(self.track_word,
help="Start tracking a word", usage="<word>", min_args=1,
help="Start tracking a word",
usage="<word>",
permission="track-word") permission="track-word")
bot.events.on("received").on("command").on("wordusers" bot.events.on("received").on("command").on("wordusers"
).hook(self.word_users, min_args=1, ).hook(self.word_users,
min_args=1,
help="Show who has used a tracked word the most", help="Show who has used a tracked word the most",
usage="<word>") usage="<word>")
@ -43,8 +49,10 @@ class Module(object):
word_count = user.get_setting(setting, 0) word_count = user.get_setting(setting, 0)
word_count += 1 word_count += 1
user.set_setting(setting, word_count) user.set_setting(setting, word_count)
def channel_message(self, event): def channel_message(self, event):
self._channel_message(event["user"], event) self._channel_message(event["user"], event)
def self_channel_message(self, event): def self_channel_message(self, event):
self._channel_message(event["server"].get_user( self._channel_message(event["server"].get_user(
event["server"].nickname), event) event["server"].nickname), event)
@ -86,7 +94,8 @@ class Module(object):
top_10 = sorted(word_users.keys()) top_10 = sorted(word_users.keys())
top_10 = sorted(top_10, key=word_users.get, reverse=True)[:10] top_10 = sorted(top_10, key=word_users.get, reverse=True)[:10]
top_10 = ", ".join("%s (%d)" % (Utils.prevent_highlight(event[ top_10 = ", ".join("%s (%d)" % (Utils.prevent_highlight(event[
"server"].get_user(nickname).nickname), word_users[nickname] "server"].get_user(
nickname).nickname), word_users[nickname]
) for nickname in top_10) ) for nickname in top_10)
event["stdout"].write("Top '%s' users: %s" % (word, top_10)) event["stdout"].write("Top '%s' users: %s" % (word, top_10))
else: else:

View file

@ -16,12 +16,14 @@ URL_YOUTUBESHORT = "https://youtu.be/%s"
ARROW_UP = "" ARROW_UP = ""
ARROW_DOWN = "" ARROW_DOWN = ""
class Module(object): class Module(object):
def __init__(self, bot): def __init__(self, bot):
self.bot = bot self.bot = bot
bot.events.on("received").on("command").on("yt", "youtube" bot.events.on("received").on("command").on("yt", "youtube"
).hook(self.yt, ).hook(self.yt,
help="Find a video on youtube", usage="[query]") help="Find a video on youtube",
usage="[query]")
bot.events.on("received").on("message").on("channel").hook( bot.events.on("received").on("message").on("channel").hook(
self.channel_message) self.channel_message)
@ -30,11 +32,14 @@ class Module(object):
help="Disable/Enable automatically getting info from youtube URLs", help="Disable/Enable automatically getting info from youtube URLs",
validate=Utils.bool_or_none) validate=Utils.bool_or_none)
def get_video_page(self, video_id, part): def get_video_page(self, video_id, part):
return Utils.get_url(URL_YOUTUBEVIDEO, get_params={"part": part, return Utils.get_url(URL_YOUTUBEVIDEO, get_params={"part": part,
"id": video_id, "key": self.bot.config["google-api-key"]}, "id": video_id,
"key":
self.bot.config[
"google-api-key"]},
json=True) json=True)
def video_details(self, video_id): def video_details(self, video_id):
snippet = self.get_video_page(video_id, "snippet") snippet = self.get_video_page(video_id, "snippet")
if snippet["items"]: if snippet["items"]:
@ -57,14 +62,18 @@ class Module(object):
match = re.match(REGEX_ISO8601, video_duration) match = re.match(REGEX_ISO8601, video_duration)
video_duration = "" video_duration = ""
video_duration += "%s:" % match.group(1)[:-1].zfill(2 video_duration += "%s:" % match.group(1)[:-1].zfill(2
) if match.group(1) else "" ) if match.group(
1) else ""
video_duration += "%s:" % match.group(2)[:-1].zfill(2 video_duration += "%s:" % match.group(2)[:-1].zfill(2
) if match.group(2) else "00:" ) if match.group(
2) else "00:"
video_duration += "%s" % match.group(3)[:-1].zfill(2 video_duration += "%s" % match.group(3)[:-1].zfill(2
) if match.group(3) else "00" ) if match.group(
3) else "00"
return "%s (%s) uploaded by %s, %s views%s %s" % ( return "%s (%s) uploaded by %s, %s views%s %s" % (
video_title, video_duration, video_uploader, "{:,}".format( video_title, video_duration, video_uploader, "{:,}".format(
int(video_views)), video_opinions, URL_YOUTUBESHORT % video_id) int(video_views)), video_opinions,
URL_YOUTUBESHORT % video_id)
def yt(self, event): def yt(self, event):
video_id = None video_id = None
@ -74,13 +83,17 @@ class Module(object):
else: else:
last_youtube = event["buffer"].find(REGEX_YOUTUBE) last_youtube = event["buffer"].find(REGEX_YOUTUBE)
if last_youtube: if last_youtube:
video_id = re.search(REGEX_YOUTUBE, last_youtube.message).group(1) video_id = re.search(REGEX_YOUTUBE, last_youtube.message).group(
1)
if search or video_id: if search or video_id:
if not video_id: if not video_id:
search_page = Utils.get_url(URL_YOUTUBESEARCH, search_page = Utils.get_url(URL_YOUTUBESEARCH,
get_params={"q": search, "part": "snippet", get_params={"q": search,
"maxResults": "1", "type": "video", "part": "snippet",
"key": self.bot.config["google-api-key"]}, "maxResults": "1",
"type": "video",
"key": self.bot.config[
"google-api-key"]},
json=True) json=True)
if search_page: if search_page:
if search_page["pageInfo"]["totalResults"] > 0: if search_page["pageInfo"]["totalResults"] > 0:
@ -104,4 +117,5 @@ class Module(object):
if video_details: if video_details:
self.bot.events.on("send").on("stdout").call(target=event[ self.bot.events.on("send").on("stdout").call(target=event[
"channel"], message=video_details, module_name="Youtube", "channel"], message=video_details, module_name="Youtube",
server=event["server"]) server=event[
"server"])