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):
def __init__(self, bot):
bot.events.on("received").on("invite").hook(

View file

@ -1,17 +1,22 @@
class Module(object):
def __init__(self, bot):
self.bot = bot
bot.events.on("received").on("command").on("changenickname"
).hook(self.change_nickname, permission="changenickname",
min_args=1, help="Change my nickname", usage="<nickname>")
).hook(self.change_nickname,
permission="changenickname",
min_args=1,
help="Change my nickname",
usage="<nickname>")
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",
usage="<raw line>")
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",
usage="<#channel>")

View file

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

View file

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

View file

@ -1,4 +1,4 @@
#--require-config bitly-api-key
# --require-config bitly-api-key
import re
import Utils
@ -6,12 +6,15 @@ import Utils
URL_BITLYSHORTEN = "https://api-ssl.bitly.com/v3/shorten"
REGEX_URL = re.compile("https?://", re.I)
class Module(object):
def __init__(self, bot):
self.bot = bot
bot.events.on("get").on("shortlink").hook(self.shortlink)
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>")
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"
REGEX_BOOKID = re.compile("id=([\w\-]+)")
class Module(object):
_name = "ISBN"
def __init__(self, bot):
self.bot = bot
bot.events.on("received").on("command").on("isbn").hook(

View file

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

View file

@ -1,5 +1,3 @@
class Module(object):
def __init__(self, bot):
bot.events.on("received.numeric.001").hook(
@ -15,7 +13,8 @@ class Module(object):
keys_sorted = list(map(lambda x: x[1],
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)):
channel = channels_sorted[i]

View file

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

View file

@ -5,7 +5,7 @@ SIDES = {"heads": 0, "tails": 1}
DEFAULT_REDEEM_DELAY = 600 # 600 seconds, 10 minutes
DEFAULT_REDEEM_AMOUNT = "100.0"
DEFAULT_INTEREST_RATE = "0.01"
INTEREST_INTERVAL = 60*60 # 1 hour
INTEREST_INTERVAL = 60 * 60 # 1 hour
DECIMAL_ZERO = decimal.Decimal("0")
REGEX_FLOAT = re.compile("\d+(?:\.\d{1,2}|$)")
@ -25,6 +25,7 @@ THIRD_COLUMN = list(range(1, 37))[2::3]
REGEX_STREET = re.compile("street([1-9]|1[0-2])$")
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -40,8 +41,11 @@ class Module(object):
bot.events.on("received.command.redeemcoins").hook(
self.redeem_coins, help="Redeem free coins")
bot.events.on("received.command.flip").hook(self.flip,
help="Bet coins on a coin flip", usage=
"heads|tails <coin amount>", min_args=2, protect_registered=True)
help="Bet coins on a coin flip",
usage=
"heads|tails <coin amount>",
min_args=2,
protect_registered=True)
bot.events.on("received.command.sendcoins").hook(
self.send, min_args=2, help="Send coins to a user",
usage="<nickname> <amount>", authenticated=True)
@ -50,12 +54,12 @@ class Module(object):
usage="<type> <amount>", protect_registered=True)
now = datetime.datetime.now()
until_next_hour = 60-now.second
until_next_hour += ((60-(now.minute+1))*60)
until_next_hour = 60 - now.second
until_next_hour += ((60 - (now.minute + 1)) * 60)
bot.events.on("timer").on("coin-interest").hook(self.interest)
bot.add_timer("coin-interest", INTEREST_INTERVAL, persist=False,
next_due=time.time()+until_next_hour)
next_due=time.time() + until_next_hour)
def coins(self, event):
if event["args_split"]:
@ -64,7 +68,8 @@ class Module(object):
target = event["user"]
coins = decimal.Decimal(target.get_setting("coins", "0.0"))
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):
target = event["server"].get_user(event["args_split"][0])
@ -76,7 +81,6 @@ class Module(object):
target.del_setting("coins")
event["stdout"].write("Reset coins for %s" % target.nickname)
def richest(self, event):
all_coins = event["server"].get_all_user_settings("coins", [])
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(top_10, key=all_coins.get, reverse=True)[:10]
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)
event["stdout"].write("Richest users: %s" % top_10)
@ -99,19 +104,21 @@ class Module(object):
redeem_delay = event["server"].get_setting("redeem-delay",
DEFAULT_REDEEM_DELAY)
if last_redeem == None or (time.time()-last_redeem
if last_redeem == None or (time.time() - last_redeem
) >= redeem_delay:
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(
user_coins+redeem_amount))
user_coins + redeem_amount))
event["stdout"].write("Redeemed %s coins" % "{0:.2f}".format(
redeem_amount))
event["user"].set_setting("last-redeem", time.time())
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" %
Utils.to_pretty_time(math.ceil(time_left)))
Utils.to_pretty_time(
math.ceil(time_left)))
else:
event["stderr"].write(
"You can only redeem coins when you have none")
@ -145,12 +152,12 @@ class Module(object):
win = side_name == chosen_side
if win:
event["user"].set_setting("coins", str(user_coins+coin_bet))
event["user"].set_setting("coins", str(user_coins + coin_bet))
event["stdout"].write("%s flips %s and wins %s coin%s!" % (
event["user"].nickname, side_name, coin_bet_str,
"" if coin_bet == 1 else "s"))
else:
event["user"].set_setting("coins", str(user_coins-coin_bet))
event["user"].set_setting("coins", str(user_coins - coin_bet))
event["stdout"].write("%s flips %s and loses %s coin%s!" % (
event["user"].nickname, side_name, coin_bet_str,
"" if coin_bet == 1 else "s"))
@ -172,7 +179,7 @@ class Module(object):
"0.0"))
redeem_amount = decimal.Decimal(event["server"].get_setting(
"redeem-amount", DEFAULT_REDEEM_AMOUNT))
new_user_coins = user_coins-send_amount
new_user_coins = user_coins - send_amount
if new_user_coins == DECIMAL_ZERO:
event["stderr"].write("You have no coins")
@ -191,7 +198,7 @@ class Module(object):
target_user_coins = decimal.Decimal(target_user_coins)
event["user"].set_setting("coins", str(new_user_coins))
target_user.set_setting("coins", str(target_user_coins+send_amount))
target_user.set_setting("coins", str(target_user_coins + send_amount))
event["stdout"].write("%s sent %s coins to %s" % (
event["user"].nickname, "{0:.2f}".format(send_amount),
@ -208,7 +215,7 @@ class Module(object):
for nickname, coins in all_coins:
coins = decimal.Decimal(coins)
if coins > redeem_amount:
coins += round(coins*interest_rate, 2)
coins += round(coins * interest_rate, 2)
server.get_user(nickname).set_setting("coins",
str(coins))
event["timer"].redo()
@ -252,7 +259,7 @@ class Module(object):
losses = {}
if choice == 0:
loss = sum(bet_amounts)
event["user"].set_setting("coins", str(user_coins-loss))
event["user"].set_setting("coins", str(user_coins - loss))
event["stdout"].write("Roulette spin lands on 0, "
"the house wins, %s loses %s" % (
event["user"].nickname, loss))
@ -264,34 +271,34 @@ class Module(object):
street_match = REGEX_STREET.match(bet)
odds = 0
if bet == "even":
odds = 1*((choice % 2) == 0)
odds = 1 * ((choice % 2) == 0)
elif bet == "odd":
odds = 1*((choice % 2) == 1)
odds = 1 * ((choice % 2) == 1)
elif bet == "red":
odds = 1*(choice in RED)
odds = 1 * (choice in RED)
elif bet == "black":
odds = 1*(choice in BLACK)
odds = 1 * (choice in BLACK)
elif bet == "small" or bet == "low":
odds = 1*(choice in SMALL)
odds = 1 * (choice in SMALL)
elif bet == "big" or bet == "high":
odds = 1*(choice in BIG)
odds = 1 * (choice in BIG)
elif bet == "dozen1":
odds = 2*(choice in FIRST_DOZEN)
odds = 2 * (choice in FIRST_DOZEN)
elif bet == "dozen2":
odds = 2*(choice in SECOND_DOZEN)
odds = 2 * (choice in SECOND_DOZEN)
elif bet == "dozen3":
odds = 2*(choice in THIRD_DOZEN)
odds = 2 * (choice in THIRD_DOZEN)
elif bet == "column1":
odds = 2*(choice in FIRST_COLUMN)
odds = 2 * (choice in FIRST_COLUMN)
elif bet == "column2":
odds = 2*(choice in SECOND_COLUMN)
odds = 2 * (choice in SECOND_COLUMN)
elif bet == "column3":
odds = 2*(choice in THIRD_COLUMN)
odds = 2 * (choice in THIRD_COLUMN)
elif street_match:
row = int(street_match.group(1))
odds = 11*(((row*3)-2) <= choice <= (row*3))
odds = 11 * (((row * 3) - 2) <= choice <= (row * 3))
elif bet.isdigit() and (1 <= int(bet) <= 36):
odds = 35*(choice == int(bet))
odds = 35 * (choice == int(bet))
else:
event["stderr"].write("Unknown bet")
failed = True
@ -299,32 +306,41 @@ class Module(object):
if odds == 0:
losses[bet] = bet_amounts[i]
else:
winnings[bet] = [odds, bet_amounts[i]*odds]
winnings[bet] = [odds, bet_amounts[i] * odds]
if failed:
return
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_losses = sum([loss for loss in losses.values()])
total_winnings_str = " (%s total)" % coin_winnings if len(
winnings.keys()) > 1 else ""
new_user_coins = (user_coins-coin_losses)+coin_winnings
new_user_coins = (user_coins - coin_losses) + coin_winnings
event["user"].set_setting("coins", str(new_user_coins))
choice = "%d %s" % (choice, colour)
if not losses and winnings:
event["stdout"].write("Roulette spin lands on %s, "
"%s wins %s%s" % (choice, event["user"].nickname,
", ".join(winnings_str), str(total_winnings_str)))
"%s wins %s%s" % (
choice, event["user"].nickname,
", ".join(winnings_str),
str(total_winnings_str)))
elif losses and winnings:
event["stdout"].write("Roulette spin lands on %s, "
"%s wins %s%s; loses %s" % (choice,
event["user"].nickname, ", ".join(winnings_str),
str(total_winnings_str), str(coin_losses)))
event[
"user"].nickname,
", ".join(
winnings_str),
str(
total_winnings_str),
str(coin_losses)))
else:
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)))

View file

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

View file

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

View file

@ -1,9 +1,10 @@
#--require-config wordnik-api-key
# --require-config wordnik-api-key
import Utils
URL_WORDNIK = "http://api.wordnik.com:80/v4/word.json/%s/definitions"
class Module(object):
def __init__(self, bot):
self.bot = bot

View file

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

View file

@ -56,7 +56,8 @@ class Module(object):
for server in self.bot.servers.values():
for channel in server.channels.values():
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
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)
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
max_duck_time = int(max_duck_time) if isinstance(max_duck_time, str) else max_duck_time
min_duck_time = int(min_duck_time) if isinstance(min_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[max_time] = max_duck_time
@ -84,25 +87,28 @@ class Module(object):
min = "min-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", [str(max), str(self.duck_times[max])]);
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",
[str(max), str(self.duck_times[max])]);
return random.randint(self.duck_times[min], self.duck_times[max])
def decoy_time(self):
return random.randint(300, 700)
return random.randint(10, 20)
def duck_bef(self, event):
target = event["user"].nickname
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:
event["stderr"].set_prefix("Kick")
if event["server"].has_user(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:
event["stderr"].write("Nope.")
else:
@ -116,8 +122,9 @@ class Module(object):
grammar = "" if befriended_ducks == 0 else "s"
event["stdout"].write(
target + ", you've befriended " + str(befriended_ducks + 1) + " duck" + grammar + " in " + event[
"target"].name);
target + ", you've befriended " + str(
befriended_ducks + 1) + " duck" + grammar + " in " + event[
"target"].name)
next_duck_time = self.duck_time(event)
self.bot.add_timer("duck-appear", next_duck_time, persist=False)
@ -128,7 +135,8 @@ class Module(object):
event["stderr"].set_prefix("Kick")
if event["server"].has_user(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:
event["stderr"].write("Nope.")
else:
@ -142,7 +150,9 @@ class Module(object):
grammar = "" if shot_ducks == 0 else "s"
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)
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 channel in server.channels.values():
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:
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 = 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:
ducks = [
@ -181,7 +194,8 @@ class Module(object):
channel.set_setting("active-duck", 0)
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):
ducks = [
@ -194,12 +208,15 @@ class Module(object):
"・ ゜・。 。・゜゜ \_ó< beep beep!"
]
event["target"].send_message(random.choice(ducks))
event["channel"].send_message(random.choice(ducks))
def set_decoy(self, event):
channel = event["target"]
next_decoy_time = self.decoy_time()
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):
# if event["args_split"]:

View file

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

View file

@ -1,15 +1,17 @@
#--require-config google-api-key
#--require-config google-search-id
# --require-config google-api-key
# --require-config google-search-id
import Utils
URL_GOOGLESEARCH = "https://www.googleapis.com/customsearch/v1"
class Module(object):
def __init__(self, bot):
self.bot = bot
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]")
def google(self, event):

View file

@ -1,10 +1,12 @@
import hashlib
class Module(object):
def __init__(self, bot):
self.bot = bot
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>")
def hash(self, event):

View file

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

View file

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

View file

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

View file

@ -1,9 +1,10 @@
import time
import Utils
SECONDS_MAX = Utils.SECONDS_WEEKS*8
SECONDS_MAX = Utils.SECONDS_WEEKS * 8
SECONDS_MAX_DESCRIPTION = "8 weeks"
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -17,11 +18,13 @@ class Module(object):
message = " ".join(event["args_split"][1:])
if seconds:
if seconds <= SECONDS_MAX:
due_time = int(time.time())+seconds
due_time = int(time.time()) + seconds
self.bot.add_timer("in", seconds,
target=event["target"].name, due_time=due_time,
server_id=event["server"].id, nickname=event["user"].nickname,
target=event["target"].name,
due_time=due_time,
server_id=event["server"].id,
nickname=event["user"].nickname,
message=message)
event["stdout"].write("Saved")
else:

View file

@ -1,5 +1,3 @@
class Module(object):
def __init__(self, bot):
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,})$")
KARMA_DELAY_SECONDS = 3
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -30,7 +31,7 @@ class Module(object):
match = re.match(REGEX_KARMA, event["message"].strip())
if match and not event["action"]:
verbose = event["channel"].get_setting("karma-verbose", False)
if not event["user"].last_karma or (time.time()-event["user"
if not event["user"].last_karma or (time.time() - event["user"
].last_karma) >= KARMA_DELAY_SECONDS:
target = match.group(1).lower().strip()
if not target == event["user"].name and target:
@ -52,10 +53,13 @@ class Module(object):
event["user"].last_karma = time.time()
elif verbose:
if target:
self.bot.events.on("send").on("stderr").call(module_name="Karma",
target=event["channel"], message="You cannot change your own karma")
self.bot.events.on("send").on("stderr").call(
module_name="Karma",
target=event["channel"],
message="You cannot change your own karma")
elif verbose:
event["stderr"].write("Try again in a couple of seconds")
def karma(self, event):
if event["args"]:
target = event["args"]

View file

@ -1,9 +1,10 @@
#--require-config lastfm-api-key
# --require-config lastfm-api-key
import Utils
URL_SCROBBLER = "http://ws.audioscrobbler.com/2.0/"
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -13,7 +14,8 @@ class Module(object):
help="Set username on last.fm")
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",
usage="[username]")

View file

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

View file

@ -1,13 +1,18 @@
import base64
import EventManager
class Module(object):
def __init__(self, bot):
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"
).hook(self.set_nickserv, min_args=1, permission="setnickserv",
help="Set bot's nickserv password", usage="<password>",
).hook(self.set_nickserv,
min_args=1,
permission="setnickserv",
help="Set bot's nickserv password",
usage="<password>",
private_only=True)
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'
class Module(object):
_name = "NR"
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):
self.bot = bot
self._client = None
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)",
usage="<crs_id>")
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)",
usage="<service_id>")
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)",
usage="<headcode>")
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)",
usage="<code>")
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("nrservice").hook(self.service)
bot.events.on("telegram").on("command").on("nrservice").hook(
self.service)
@property
def client(self):
@ -70,11 +77,11 @@ class Module(object):
else:
params[arg.replace("!", "")] = '!' not in arg
ret = {k: v[0] for k,v in defaults.items()}
ret = {k: v[0] for k, v in defaults.items()}
ret["default"] = True
ret["errors"] = []
for k,v in params.items():
for k, v in params.items():
if not k in defaults.keys():
ret["errors"].append((k, "Invalid parameter"))
continue
@ -83,7 +90,8 @@ class Module(object):
continue
ret["default"] = False
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
def process(self, service):
@ -100,10 +108,12 @@ class Module(object):
times[a] = {"orig": service[a]}
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:
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"
)
times[a]["ut"] = times[a]["datetime"].timestamp()
@ -112,17 +122,22 @@ class Module(object):
for k, a in times.items():
if not a["orig"]: continue
a["short"] = a["datetime"].strftime("%H%M") if len(a["orig"]) > 5 else a["orig"]
a["shortest"] = "%02d" % a["datetime"].minute if -300 < a["ut"]-ut_now < 1800 else a["short"]
a["short"] = a["datetime"].strftime("%H%M") if len(
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["estimate"] = k[0] == "e"
a["schedule"] = k[0] == "s"
a["on_time"] = a["ut"] - times["s"+ k[1:]]["ut"] < 300
a["on_time"] = a["ut"] - times["s" + k[1:]]["ut"] < 300
a["status"] = 1 if a["on_time"] else 2
if "a" + k[1:] in service: a["status"] = {"d": 0, "a": 3}[k[2]]
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["departure"] = (dep + arr + [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"])}
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):
client = self.client
@ -143,30 +162,51 @@ class Module(object):
schedule = {}
location_code = event["args_split"][0].upper()
filter = self.filter(' '.join(event["args_split"][1:]) if len(event["args_split"]) > 1 else "", {
"dest": ('', lambda x: x.isalpha() and len(x)==3),
"origin":('', 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)),
filter = self.filter(' '.join(event["args_split"][1:]) if len(
event["args_split"]) > 1 else "", {
"dest": (
'', lambda x: x.isalpha() and len(x) == 3),
"origin": (
'', 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),
"type": ("departure", lambda x: x in ["departure", "arrival", "both"]),
"terminating": (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),
"tops": (None, lambda x: len(x)<4 and x.isdigit()),
"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))
"type": ("departure",
lambda x: x in ["departure",
"arrival", "both"]),
"terminating": (
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),
"tops": (
None, lambda x: len(x) < 4 and x.isdigit()),
"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))
})
if filter["errors"]:
return event["stderr"].write("Filter: " + filter["errors_summary"])
if filter["inter"] and filter["type"]!="departure":
return event["stderr"].write("Filtering by intermediate stations is only supported for departures.")
if filter["inter"] and filter["type"] != "departure":
return event["stderr"].write(
"Filtering by intermediate stations is only supported for departures.")
nr_filterlist = client.factory.create("filterList")
if filter["inter"]: nr_filterlist.crs.append(filter["inter"])
@ -177,29 +217,40 @@ class Module(object):
now = now.replace(minute=int(filter["time"][2:]))
if filter["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:
query = method(100, location_code, now.isoformat().split(".")[0], filter["period"],
nr_filterlist, "to", '', "PBS", filter["nonpassenger"])
query = method(100, location_code, now.isoformat().split(".")[0],
filter["period"],
nr_filterlist, "to", '', "PBS",
filter["nonpassenger"])
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.")
else:
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"):
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"])
else:
station_summary = "%s (%s, %s%s)" % (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 ""
station_summary = "%s (%s, %s%s)" % (
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:
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"]))
trains = []
@ -209,107 +260,152 @@ class Module(object):
if "ferryServices" in query: services += query["ferryServices"][0]
for t in services:
parsed = {
"rid" : t["rid"],
"uid" : t["uid"],
"head" : t["trainid"],
"rid": t["rid"],
"uid": t["uid"],
"head": t["trainid"],
"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": "",
"toc": t["operatorCode"],
"cancelled" : t["isCancelled"] if "isCancelled" in t else False,
"delayed" : t["departureType"]=="Delayed" if "departureType" in t else None,
"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,
"bus" : t["trainid"]=="0B00",
"times" : self.process(t),
"activity" : self.reduced_activities(t["activities"]),
"cancelled": t["isCancelled"] if "isCancelled" in t else False,
"delayed": t[
"departureType"] == "Delayed" if "departureType" in t else None,
"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,
"bus": t["trainid"] == "0B00",
"times": self.process(t),
"activity": self.reduced_activities(t["activities"]),
}
parsed["destinations"] = [{"name": a["locationName"], "tiploc": a["tiploc"],
"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 ''}
parsed["destinations"] = [
{"name": a["locationName"], "tiploc": a["tiploc"],
"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]]
parsed["origins"] = [{"name": a["locationName"], "tiploc": a["tiploc"],
"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 ''}
parsed["origins"] = [
{"name": a["locationName"], "tiploc": a["tiploc"],
"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]]
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"]:
for k, time in parsed["times"].items():
time["short"], time["on_time"], time["status"], time["prefix"] = (
"%s:%s" % ("C" if parsed["cancel_reason"] else "D", parsed["cancel_reason"] or parsed["delay_reason"] or "?"),
time["short"], time["on_time"], time["status"], time[
"prefix"] = (
"%s:%s" % ("C" if parsed["cancel_reason"] else "D",
parsed["cancel_reason"] or parsed[
"delay_reason"] or "?"),
False, 2, ""
)
trains.append(parsed)
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:
for t in trains:
summary = summary_query[t["uid"]]
t.update(summary)
summary_plat = summary.get("platforms", {}).get(query["crs"])
if summary_plat and t["platform"]=="?":
summary_plat = summary.get("platforms", {}).get(
query["crs"])
if summary_plat and t["platform"] == "?":
t["platform"], t["platform_prefix"] = summary_plat, "s"
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"]])
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"]])
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 = []
train_locs_toc = []
for train in trains:
if not True in [
(train["destinations"], train["toc"]) in train_locs_toc and (filter["dedup"] or filter["default"]),
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"]],
(train["destinations"], train["toc"]) in train_locs_toc and (
filter["dedup"] or filter["default"]),
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["plat"] and not filter["plat"] == train["platform"],
filter["type"] == "departure" and train["terminating"],
filter["type"] == "arrival" and train["departure_only"],
filter["terminating"] and not train["terminating"],
filter["tops"] and not filter["tops"] in train.get("tops_possible", []),
filter["power"] and not filter["power"]==train.get("power_type", None),
filter["tops"] and not filter["tops"] in train.get(
"tops_possible", []),
filter["power"] and not filter["power"] == train.get(
"power_type", None),
]:
train_locs_toc.append((train["destinations"], train["toc"]))
trains_filtered.append(train)
if event.get("external"):
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 '',
t["times"]["both"]["prefix"] + t["times"]["both"]["short"],
"" if t["terminating"] or filter["type"]=="arrival" else "",
t["origin_summary"] if t["terminating"] or filter["type"]=="arrival" else t["dest_summary"]
"" if t["terminating"] or filter["type"] == "arrival" else "",
t["origin_summary"] if t["terminating"] or filter[
"type"] == "arrival" else t["dest_summary"]
) for t in trains_filtered])
else:
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 '',
t["origin_summary"] if t["terminating"] or filter["type"]=="arrival" else t["dest_summary"],
"from " if not filter["type"][0] in "ad" and t[
"terminating"] else '',
t["origin_summary"] if t["terminating"] or filter[
"type"] == "arrival" else t["dest_summary"],
t["uid"],
t["platform_prefix"],
"bus" if t["bus"] else t["platform"],
"*" if t["platform_hidden"] else '',
"?" if "platformsAreUnreliable" in query and query["platformsAreUnreliable"] else '',
t["times"][filter["type"]]["prefix"].replace(filter["type"][0], '') if not t["cancelled"] else "",
"?" if "platformsAreUnreliable" in query and query[
"platformsAreUnreliable"] else '',
t["times"][filter["type"]]["prefix"].replace(filter["type"][0],
'') if not t[
"cancelled"] else "",
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),
bool(t["activity"])*", " + "+".join(t["activity"]),
bool(t["activity"]) * ", " + "+".join(t["activity"]),
) for t in trains_filtered])
if event.get("external"):
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:
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):
client = self.client
@ -317,7 +413,8 @@ class Module(object):
external = event.get("external", False)
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"}
eagle_key = self.bot.config["eagle-api-key"]
@ -327,9 +424,12 @@ class Module(object):
service_id = event["args_split"][0]
filter = self.filter(' '.join(event["args_split"][1:]) if len(event["args_split"]) > 1 else "", {
"passing": (False, lambda x: type(x)==type(True)),
"type": ("arrival", lambda x: x in ["arrival", "departure"])
filter = self.filter(' '.join(event["args_split"][1:]) if len(
event["args_split"]) > 1 else "", {
"passing": (
False, lambda x: type(x) == type(True)),
"type": ("arrival", lambda x: x in ["arrival",
"departure"])
})
if filter["errors"]:
@ -338,18 +438,27 @@ class Module(object):
rid = service_id
if len(service_id) <= 8:
query = client.service.QueryServices(service_id, datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime("%H:%M:%S+0000"))
query = client.service.QueryServices(service_id,
datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime(
"%H:%M:%S+0000"))
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:
schedule = schedule_query["current"]
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:
return event["stdout"].write("Identifier refers to multiple services: " +
", ".join(["%s (%s->%s)" % (a["uid"], a["originCrs"], a["destinationCrs"]) for a in query["serviceList"][0]]))
return event["stdout"].write(
"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:
@ -357,122 +466,180 @@ class Module(object):
query = client.service.GetServiceDetailsByRID(rid)
if schedule:
sources.append("Eagle/SCHEDULE")
if not query: query = {"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 {
if not query: query = {
"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 {
"operatorCode": schedule["atoc_code"],
"serviceType": stype if stype else SCHEDULE_STATUS[schedule["status"]],
"serviceType": stype if stype else SCHEDULE_STATUS[
schedule["status"]],
}.items():
query[k] = v
disruptions = []
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:
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:
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:
disruptions = ", ".join(disruptions)
else: disruptions = ""
else:
disruptions = ""
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:
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(),
"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,
"last" : False,
"cancelled" : station["isCancelled"] if "isCancelled" in station else False,
"last": False,
"cancelled": station[
"isCancelled"] if "isCancelled" in station else False,
"associations": [],
"length": station["length"] if "length" in station else None,
"length": station[
"length"] if "length" in station else None,
"times": self.process(station),
"platform": station["platform"] if "platform" in station else None,
"activity": self.activities(station["activities"]) if "activities" in station else [],
"activity_p": self.reduced_activities(station["activities"]) if "activities" in station else [],
"platform": station[
"platform"] if "platform" in station else None,
"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"]:
parsed["times"]["arrival"].update({"short": "Cancelled", "on_time": False, "status": 2})
parsed["times"]["departure"].update({"short": "Cancelled", "on_time": False, "status": 2})
parsed["times"]["arrival"].update(
{"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:
parsed_assoc = {
"uid_assoc": assoc.uid,
"category": {"divide": "VV", "join": "JJ", "next": "NP"}[assoc["category"]],
"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,
"category":
{"divide": "VV", "join": "JJ", "next": "NP"}[
assoc["category"]],
"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_crs": assoc["destCRS"] if "destCRS" in assoc else None,
"dest_name": assoc["destination"],
"dest_tiploc": assoc["destTiploc"],
"dest_crs": assoc[
"destCRS"] if "destCRS" in assoc else None,
"far_name": assoc["destination"], "far_tiploc": assoc["destTiploc"],
"far_crs": assoc["destCRS"] if "destCRS" in assoc else None,
"far_name": assoc["destination"],
"far_tiploc": assoc["destTiploc"],
"far_crs": assoc[
"destCRS"] if "destCRS" in assoc else None,
}
if parsed_assoc["direction"]:
parsed_assoc.update({"far_name": parsed_assoc["origin_name"],
"far_tiploc": parsed_assoc["origin_tiploc"], "far_crs": parsed_assoc["origin_crs"]})
parsed_assoc.update(
{"far_name": parsed_assoc["origin_name"],
"far_tiploc": parsed_assoc["origin_tiploc"],
"far_crs": parsed_assoc["origin_crs"]})
parsed["associations"].append(parsed_assoc)
else:
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"],
"called": False,
"passing": bool(station.get("pass")),
"first": len(stations) == 0,
"last" : False,
"cancelled" : False,
"last": False,
"cancelled": False,
"length": None,
"times": self.process(station["dolphin_times"]),
"platform": station["platform"],
"associations": station["associations"] or [],
"activity": self.activities(station["activity"]),
"activity_p": self.reduced_activities(station["activity"]),
"activity_p": self.reduced_activities(
station["activity"]),
}
stations.append(parsed)
[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
for station in stations:
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"]:
station["times"]["arrival"]["status"], station["times"]["departure"]["status"] = 5, 5
station["times"]["arrival"]["status"], \
station["times"]["departure"]["status"] = 5, 5
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["passing"],
station["name"],
station["crs"] + ", " if station["name"] != station["crs"] else '',
station["length"] + " cars, " if station["length"] and (station["first"] or (station["last"]) or station["associations"]) else '',
station["crs"] + ", " if station["name"] != station[
"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 '') +
station["times"][filter["type"]]["prefix"].replace(filter["type"][0], ""),
Utils.color(colours[station["times"][filter["type"]]["status"]]),
station["times"][filter["type"]]["prefix"].replace(
filter["type"][0], ""),
Utils.color(
colours[station["times"][filter["type"]]["status"]]),
station["times"][filter["type"]]["short"],
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"]]),
)
station["summary_external"] = "%1s%-5s %1s%-5s %-3s %-3s %-3s %s%s" % (
"~"*station["times"]["a"]["estimate"] + "s"*(station["times"]["a"]["schedule"]),
station[
"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"]["d"]["estimate"] + "s"*(station["times"]["d"]["schedule"]),
"~" * station["times"]["d"]["estimate"] + "s" * (
station["times"]["d"]["schedule"]),
station["times"]["d"]["short"],
station["platform"] or '',
",".join(station["activity"]) or '',
station["crs"] or station["tiploc"],
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 = []
@ -483,8 +650,10 @@ class Module(object):
continue
stations_filtered.append(station)
if station["first"] and not station["last"] and filter["default"] and not external:
stations_filtered.append({"summary": "(...)", "summary_external": "(...)"})
if station["first"] and not station["last"] and filter[
"default"] and not external:
stations_filtered.append(
{"summary": "(...)", "summary_external": "(...)"})
done_count = len([s for s in stations if s["called"]])
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" % (
service_id, ", ".join(sources),
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])
))
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"],
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,
", ".join([s["summary"] for s in stations_filtered])))
@ -506,25 +678,40 @@ class Module(object):
client = self.client
service_id = event["args_split"][0]
query = client.service.QueryServices(service_id, datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime("%H:%M:%S+0000"))
query = client.service.QueryServices(service_id,
datetime.utcnow().date().isoformat(),
datetime.utcnow().time().strftime(
"%H:%M:%S+0000"))
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]
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:
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):
client = self.client
if not event["args"].isnumeric():
return event["stderr"].write("The delay/cancellation code must be a number")
reasons = {a["code"]:(a["lateReason"], a["cancReason"]) for a in client.service.GetReasonCodeList()[0]}
return event["stderr"].write(
"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:
event["stdout"].write("%s: %s" % (event["args"], " / ".join(reasons[event["args"]])))
event["stdout"].write(
"%s: %s" % (event["args"], " / ".join(reasons[event["args"]])))
else:
event["stdout"].write("This doesn't seem to be a valid reason code")

View file

@ -1,5 +1,6 @@
import EventManager
class Module(object):
def __init__(self, bot):
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 "
"(/msg %s register | /msg %s identify)")
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -12,13 +13,20 @@ class Module(object):
self.preprocess_command)
bot.events.on("received").on("part").hook(self.on_part)
bot.events.on("received").on("command").on("identify"
).hook(self.identify, private_only=True, min_args=1,
usage="<password>", help="Identify yourself")
).hook(self.identify,
private_only=True,
min_args=1,
usage="<password>",
help="Identify yourself")
bot.events.on("received").on("command").on("register"
).hook(self.register, private_only=True, min_args=1,
usage="<password>", help="Register your nickname")
).hook(self.register,
private_only=True,
min_args=1,
usage="<password>",
help="Register your nickname")
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(
self.my_permissions, authenticated=True)
@ -142,6 +150,7 @@ class Module(object):
target.set_setting("permissions", permissions)
event["stdout"].write("Gave permission '%s' to %s" % (
permission, target.nickname))
def remove_permission(self, event):
permission = event["args_split"][1].lower()
target, registered, permissions = self._get_user_details(

View file

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

View file

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

View file

@ -1,59 +1,60 @@
import random
QUOTES = {
"You can build a throne with bayonets, but it's difficult to sit on it." : "Boris Yeltsin",
"We don't appreciate what we have until it's gone. Freedom is like that. It's like air. When you have it, you don't notice it." : "Boris Yeltsin",
"They accused us of suppressing freedom of expression. This was a lie and we could not let them publish it." : "Nelba Blandon, as director of censorship, Nicaragua",
"Death solves all problems - no man, no problem." : "Anatoly Rybakov",
"If we don't end war, war will end us." : "H.G. Wells",
"All that is necessary for evil to succeed is for good men to do nothing." : "Edmund Burke",
"Live well. It is the greatest revenge." : "The Talmud",
"To improve is to change, so to be perfect is to have changed often." : "Winston Churchill",
"I believe it is peace for our time." : "Neville Chamberlain",
"Orbiting Earth in the spaceship, I saw how beautiful our planet is. People, let us preserve and increase this beauty, not destroy it!" : "Yuri Gagarin",
"Science is not everything, but science is very beautiful." : "Robert Oppenheimer",
"We choose to go to the Moon! We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard." : "",
"You teach a child to read, and he or her will be able to pass a literacy test." : "George W Bush",
"I know the human being and fish can coexist peacefully." : "George W Bush",
"They misunderestimated me." : "George W Bush",
"I'm an Internet expert too." : "Kim Jong Il",
"So long, and thanks for all the fish" : "",
"It is a lie that I made the people starve." : "Nicolae Ceaușescu",
"As far as I know - effective immediately, without delay." : "Günter Schabowski",
"Not all those who wander are lost." : "J.R.R. Tolkien",
"Life would be tragic if it weren't funny." : "Stephen Hawking",
"We are such stuff as dreams are made on; and our little life is rounded with a sleep." : "",
"Do androids dream of electric sheep?" : "",
"Love all, trust a few, do wrong to none." : "William Shakespeare",
"Patriotism is not enough. I must have no hatred or bitterness towards any one." : "Edith Cavell",
"The monuments of wit survive the monuments of power." : "Francis Bacon",
"Human ingenuity cannot concoct a cipher which human ingenuity cannot resolve" : "Edgar Allan Poe",
"Nobody has the intention to erect a wall" : "Walter Ulbricht",
"We're all completely fucked. I'm fucked. You're fucked. [...] It has been the biggest cock-up ever and we're all completely fucked" : "Richard Mottram",
"The security aspect of cyber is very, very tough. And maybe it's hardly doable." : "Donald Trump",
"The Internet. The hate machine, the love machine, the machine powered by many machines. We are all part of it, helping it grow, and helping it grow on us." : "Topiary",
"Every great historical event began as a utopia and ended as a reality." : "Richard Nikolaus Eijiro",
"Strange women lying in ponds distributing swords is no basis for a system of government!" : "",
"My hovercraft is full of eels." : "",
"That was only a prelude; where they burn books, they will in the end also burn people" : "Heinrich Heine",
'Never, "for the sake of peace and quiet", deny your own experience or convictions.' : "Dag Hammarskjöld",
"Quis custodiet ipsos custodes?" : "",
"Unless someone like you cares a whole awful lot, nothing is going to get better. It's not." : "Theodor Seuss Geisel",
"Wer nichts zu verbergen hat, hat auch nichts zu befürchten" : "",
"Words will always retain their power. Words offer the means to meaning, and for those who will listen, the enunciation of truth." : "Alan Moore",
"Сейчас я вам заявляю, что вы провалились!" : "",
"Godhet är något så enkelt: att alltid finnas för andra, att aldrig söka sig själv." : "Dag Hammarskjöld",
"Fire, water and government know nothing of mercy" : "",
"The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true. So I elect for neither label" : "James Branch Cabell",
"微乎微乎,至于无形;神乎神乎,至于无声;故能为敌之司命" : "孫子",
"If you know your enemy and know yourself, one hundred battles will not defeat you" : "Sun Tzu",
"Come here to this gate! Mr Gorbachev, open this gate! Mr Gorbachev, tear down this wall!" : "Ronald Reagan",
"The lamps are going out all over Europe, we shall not see them lit again in our lifetime" : "Edward Grey",
"The laws of mathematics are very commendable, but the only law that applies in Australia is the law of Australia" : "Malcolm Turnbull",
"He had to download the entire iOS system on his computer, he had to decrypt it, he had to do all of these things I don't even understand" : "Glenn Moramarco, as assistant U.S. attorney",
"I dont need to understand how encryption works" : "Amber Rudd",
"You can build a throne with bayonets, but it's difficult to sit on it.": "Boris Yeltsin",
"We don't appreciate what we have until it's gone. Freedom is like that. It's like air. When you have it, you don't notice it.": "Boris Yeltsin",
"They accused us of suppressing freedom of expression. This was a lie and we could not let them publish it.": "Nelba Blandon, as director of censorship, Nicaragua",
"Death solves all problems - no man, no problem.": "Anatoly Rybakov",
"If we don't end war, war will end us.": "H.G. Wells",
"All that is necessary for evil to succeed is for good men to do nothing.": "Edmund Burke",
"Live well. It is the greatest revenge.": "The Talmud",
"To improve is to change, so to be perfect is to have changed often.": "Winston Churchill",
"I believe it is peace for our time.": "Neville Chamberlain",
"Orbiting Earth in the spaceship, I saw how beautiful our planet is. People, let us preserve and increase this beauty, not destroy it!": "Yuri Gagarin",
"Science is not everything, but science is very beautiful.": "Robert Oppenheimer",
"We choose to go to the Moon! We choose to go to the Moon in this decade and do the other things, not because they are easy, but because they are hard.": "",
"You teach a child to read, and he or her will be able to pass a literacy test.": "George W Bush",
"I know the human being and fish can coexist peacefully.": "George W Bush",
"They misunderestimated me.": "George W Bush",
"I'm an Internet expert too.": "Kim Jong Il",
"So long, and thanks for all the fish": "",
"It is a lie that I made the people starve.": "Nicolae Ceaușescu",
"As far as I know - effective immediately, without delay.": "Günter Schabowski",
"Not all those who wander are lost.": "J.R.R. Tolkien",
"Life would be tragic if it weren't funny.": "Stephen Hawking",
"We are such stuff as dreams are made on; and our little life is rounded with a sleep.": "",
"Do androids dream of electric sheep?": "",
"Love all, trust a few, do wrong to none.": "William Shakespeare",
"Patriotism is not enough. I must have no hatred or bitterness towards any one.": "Edith Cavell",
"The monuments of wit survive the monuments of power.": "Francis Bacon",
"Human ingenuity cannot concoct a cipher which human ingenuity cannot resolve": "Edgar Allan Poe",
"Nobody has the intention to erect a wall": "Walter Ulbricht",
"We're all completely fucked. I'm fucked. You're fucked. [...] It has been the biggest cock-up ever and we're all completely fucked": "Richard Mottram",
"The security aspect of cyber is very, very tough. And maybe it's hardly doable.": "Donald Trump",
"The Internet. The hate machine, the love machine, the machine powered by many machines. We are all part of it, helping it grow, and helping it grow on us.": "Topiary",
"Every great historical event began as a utopia and ended as a reality.": "Richard Nikolaus Eijiro",
"Strange women lying in ponds distributing swords is no basis for a system of government!": "",
"My hovercraft is full of eels.": "",
"That was only a prelude; where they burn books, they will in the end also burn people": "Heinrich Heine",
'Never, "for the sake of peace and quiet", deny your own experience or convictions.': "Dag Hammarskjöld",
"Quis custodiet ipsos custodes?": "",
"Unless someone like you cares a whole awful lot, nothing is going to get better. It's not.": "Theodor Seuss Geisel",
"Wer nichts zu verbergen hat, hat auch nichts zu befürchten": "",
"Words will always retain their power. Words offer the means to meaning, and for those who will listen, the enunciation of truth.": "Alan Moore",
"Сейчас я вам заявляю, что вы провалились!": "",
"Godhet är något så enkelt: att alltid finnas för andra, att aldrig söka sig själv.": "Dag Hammarskjöld",
"Fire, water and government know nothing of mercy": "",
"The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true. So I elect for neither label": "James Branch Cabell",
"微乎微乎,至于无形;神乎神乎,至于无声;故能为敌之司命": "孫子",
"If you know your enemy and know yourself, one hundred battles will not defeat you": "Sun Tzu",
"Come here to this gate! Mr Gorbachev, open this gate! Mr Gorbachev, tear down this wall!": "Ronald Reagan",
"The lamps are going out all over Europe, we shall not see them lit again in our lifetime": "Edward Grey",
"The laws of mathematics are very commendable, but the only law that applies in Australia is the law of Australia": "Malcolm Turnbull",
"He had to download the entire iOS system on his computer, he had to decrypt it, he had to do all of these things I don't even understand": "Glenn Moramarco, as assistant U.S. attorney",
"I dont need to understand how encryption works": "Amber Rudd",
}
class Module(object):
def __init__(self, bot):
bot.events.on("get.quit-quote").hook(self.quote)
@ -61,4 +62,3 @@ class Module(object):
def quote(self, event):
quote = random.choice(list(QUOTES.items()))
return (" - " if quote[1] else "").join(quote)

View file

@ -1,22 +1,27 @@
import random, time
class Module(object):
def __init__(self, bot):
self.bot = bot
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",
usage="<category> = <quote>")
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",
usage="<category> = <search>")
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",
usage="<category> = <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",
usage="<category>")
@ -47,7 +52,9 @@ class Module(object):
found.append(quote)
if 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:
event["stderr"].write("No quotes found")
else:
@ -78,7 +85,7 @@ class Module(object):
category = event["args"].strip().lower()
quotes = event["server"].get_setting("quotes-%s" % category, [])
if quotes:
index = random.randint(0, len(quotes)-1)
index = random.randint(0, len(quotes) - 1)
nickname, time_added, quote = quotes[index]
event["stdout"].write("%s: %s" % (category, quote))
else:

View file

@ -1,13 +1,17 @@
import random, uuid
class Module(object):
_name = "Random"
def __init__(self, bot):
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]")
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):
start, end = "1", "100"

View file

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

View file

@ -4,6 +4,7 @@ import Utils
REGEX_SPLIT = re.compile("(?<!\\\\)/")
REGEX_SED = re.compile("^s/")
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -17,7 +18,8 @@ class Module(object):
bot.events.on("postboot").on("configure").on(
"channelset").assure_call(setting="sed-sender-only",
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):
sed_split = re.split(REGEX_SPLIT, event["message"], 3)
@ -59,7 +61,8 @@ class Module(object):
event, "sed-sender-only", False
) else None
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:
new_message = re.sub(pattern, replace, line.message, count)
if line.action:
@ -68,4 +71,6 @@ class Module(object):
prefix = "<%s>" % line.sender
self.bot.events.on("send").on("stdout").call(target=event[
"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 Utils
class Module(object):
def __init__(self, bot):
bot.events.on("received").on("message").on("channel"
@ -18,7 +19,7 @@ class Module(object):
seen_seconds = event["server"].get_user(event["args_split"][0]
).get_setting("seen")
if seen_seconds:
since = Utils.to_pretty_time(time.time()-seen_seconds,
since = Utils.to_pretty_time(time.time() - seen_seconds,
max_units=2)
event["stdout"].write("%s was last seen %s ago" % (
event["args_split"][0], since))

View file

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

View file

@ -1,5 +1,6 @@
import signal
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -8,7 +9,8 @@ class Module(object):
def SIGINT(self, signum, frame):
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():
reason = "Leaving"

View file

@ -1,4 +1,4 @@
#--require-config soundcloud-api-key
# --require-config soundcloud-api-key
import json, re, time
import Utils
@ -7,12 +7,15 @@ URL_SOUNDCLOUD_TRACK = "http://api.soundcloud.com/tracks"
URL_SOUNDCLOUD_RESOLVE = "http://api.soundcloud.com/resolve"
REGEX_SOUNDCLOUD = "https?://soundcloud.com/([^/]+)/([^/]+)"
class Module(object):
_name = "SoundCloud"
def __init__(self, bot):
self.bot = bot
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):
query = None
@ -51,11 +54,12 @@ class Module(object):
title = page["title"]
user = page["user"]["username"]
duration = time.strftime("%H:%M:%S", time.gmtime(page[
"duration"]/1000))
"duration"] / 1000))
if duration.startswith("00:"):
duration = duration[3:]
link = page["permalink_url"]
event["stdout"].write("%s [%s] (posted by %s) %s" % (title,
duration, user, link))
duration, user,
link))
else:
event["stderr"].write("Failed to load results")

View file

@ -3,6 +3,7 @@ import Utils
URL_SPOTIFY = "https://api.spotify.com/v1/search"
class Module(object):
def __init__(self, bot):
bot.events.on("received").on("command").on("spotify").hook(
@ -11,7 +12,9 @@ class Module(object):
def spotify(self, event):
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 len(page["tracks"]["items"]):
item = page["tracks"]["items"][0]

View file

@ -1,17 +1,20 @@
import time
import Utils
class Module(object):
def __init__(self, bot):
self.boot_time = time.time()
self.bot = bot
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"
).hook(self.stats, help="Show my network/channel/user stats")
).hook(self.stats,
help="Show my network/channel/user stats")
def uptime(self, event):
seconds = int(time.time()-self.boot_time)
seconds = int(time.time() - self.boot_time)
event["stdout"].write("Uptime: %s" % Utils.to_pretty_time(
seconds))
@ -23,7 +26,6 @@ class Module(object):
channels += len(server.channels)
users += len(server.users)
response = "I currently have %d network" % networks
if networks > 1:
response += "s"

View file

@ -4,41 +4,64 @@ import random
class Module(object):
def __init__(self, bot):
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):
suggestion_greeting = ["Might I suggest", "Can I suggest", "Should we attack immediately with"]
command_greeting = ["We should attack now with", "We must attack now with", "I suggest attacking with",
suggestion_greeting = ["Might I suggest", "Can I suggest",
"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"]
method_of_attack_a = ["full-frontal", "pincer", "surprise", "brutally excessive", "multi-pronged", "glorious",
"violent", "devastating", "superior", "fast-paced", "fleet-wide", "stealth",
"diversionary", "exceptional", "point-blank", "night time"]
method_of_attack_an = ["acid-heavy", "immediate", "overwhelming", "unstoppable", "underground", "arial",
method_of_attack_a = ["full-frontal", "pincer", "surprise",
"brutally excessive", "multi-pronged", "glorious",
"violent", "devastating", "superior",
"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"]
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"]
attack_adjective = ["laser", "berserker", "acid", "armoured attack", "proton",
attack_adjective = ["laser", "berserker", "acid", "armoured attack",
"proton",
"three kinds of", "atomic", "toxic", "explosive",
"red-hot", "thermal", "automated fire", "cluster",
"enhanced germ", "energy-drink-fueled", "battle ready", "Sontaran", "military"]
attack_object = ["bees", "chainsaws", "marmots", "acid", "monkeys", "mines", "bombs", "snakes", "spiders",
"knives", "rockets", "sharks", "owls", "repurposed cybermats", "cannons", "alligators", "ants",
"gorillas", "genetically enhanced cyber-elephants", "mechanoids", "KGB agents",
"enhanced germ", "energy-drink-fueled",
"battle ready", "Sontaran", "military"]
attack_object = ["bees", "chainsaws", "marmots", "acid", "monkeys",
"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"]
attack_object_two = ["robots", "ninjas", "grenades", "a dolphin full of napalm", "dynamite",
"xenomorphs", "lots and lots of C4", "tactical nukes", "bio-weapons",
"rocket launchers", "an elephant", "a memory worm for afterwards", "this pencil"]
attack_object_two = ["robots", "ninjas", "grenades",
"a dolphin full of napalm", "dynamite",
"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(
method_of_attack_a)
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 "!"
suggestion = greeting + method_of_attack + " " + random.choice(type_of_attack) + " with " + random.choice(
attack_adjective) + " " + random.choice(attack_object) + " and " + random.choice(
suggestion = greeting + method_of_attack + " " + random.choice(
type_of_attack) + " with " + random.choice(
attack_adjective) + " " + random.choice(
attack_object) + " and " + random.choice(
attack_object_two) + exclamation
event["stdout"].write(suggestion)

View file

@ -5,6 +5,7 @@ import json
from datetime import datetime
from threading import Thread
class Module(Thread):
_name = "telegram"
@ -26,7 +27,8 @@ class Module(Thread):
dolphin.events.on("signal").on("interrupt").hook(self.sigint)
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):
message, text = update.message, update.message.text
@ -45,18 +47,23 @@ class Module(Thread):
"stderr": IOWrapper(bot, message.chat_id, message.message_id),
"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):
self.updater.stop()
class IOWrapper:
def __init__(self, bot, chat_id, message_id):
self.bot = bot
self.chat_id = chat_id
self.message_id = message_id
def write(self, text):
if len(text)>4096-10:
if len(text) > 4096 - 10:
text = text[:4086] + ""
self.bot.send_message(chat_id=self.chat_id, text="```\n" + text + "\n```",
reply_to_message_id=self.message_id, parse_mode="Markdown")
self.bot.send_message(chat_id=self.chat_id,
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 = "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_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"
PLATFORM_TYPES = ["Northbound", "Southbound", "Eastbound", "Westbound", "Inner Rail", "Outer Rail"]
PLATFORM_TYPES = ["Northbound", "Southbound", "Eastbound", "Westbound",
"Inner Rail", "Outer Rail"]
class Module(object):
_name = "TFL"
def __init__(self, bot):
self.bot = bot
self.result_map = {}
@ -32,11 +37,13 @@ class Module(object):
help="Get line status for TfL underground lines",
usage="<line_name>")
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",
usage="<name>")
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",
usage="<ID>")
bot.events.on("received").on("command").on("tflstop"
@ -44,24 +51,29 @@ class Module(object):
help="Get information for a given stop",
usage="<stop_id>")
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",
usage="<service index>")
def vehicle_span(self, arrival_time, human=True):
vehicle_due_iso8601 = arrival_time
if "." in vehicle_due_iso8601:
vehicle_due_iso8601 = vehicle_due_iso8601.split(".")[0]+"Z"
vehicle_due_iso8601 = vehicle_due_iso8601.split(".")[0] + "Z"
vehicle_due = datetime.datetime.strptime(vehicle_due_iso8601,
"%Y-%m-%dT%H:%M:%SZ")
time_until = vehicle_due-datetime.datetime.utcnow()
time_until = int(time_until.total_seconds()/60)
time_until = vehicle_due - datetime.datetime.utcnow()
time_until = int(time_until.total_seconds() / 60)
if time_until == 0: human_time = "due"
else: human_time = "in %s min" % time_until
if time_until == 0:
human_time = "due"
else:
human_time = "in %s min" % time_until
if human: return human_time
else: return time_until
if human:
return human_time
else:
return time_until
def platform(self, platform, short=False):
p = re.compile("(?:(.*) - Platform (\\d+)|(.*bound) Platform (\\d+))")
@ -103,16 +115,23 @@ class Module(object):
for bus in bus_stop:
bus_number = bus["lineName"]
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
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"],
"destination": destination, "human_time": human_time, "mode": bus["modeName"],
busses.append({"route": bus_number, "time": time_until,
"id": bus["vehicleId"],
"destination": destination,
"human_time": human_time,
"mode": bus["modeName"],
"platform": bus["platformName"],
"platform_short" : self.platform(bus["platformName"], short=True)})
"platform_short": self.platform(
bus["platformName"], short=True)})
if busses:
busses = sorted(busses, key=lambda b: b["time"])
busses_filtered = []
@ -122,11 +141,14 @@ class Module(object):
# dedup if target route isn't "*", filter if target route isn't None or "*"
for b in busses:
if target_bus_route != "*":
if (b["route"], b["destination"]) in bus_route_dest: continue
if bus_route_plat.count((b["route"], b["platform"])) >= 2: continue
if (b["route"],
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_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)
else:
busses_filtered.append(b)
@ -134,7 +156,8 @@ class Module(object):
self.result_map[event["target"].id] = busses_filtered
# 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])
event["stdout"].write("%s (%s): %s" % (stop_name, stop_id,
@ -177,7 +200,9 @@ class Module(object):
for status in statuses:
for arg in event["args_split"]:
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:
event["stdout"].write(result[:-2])
else:
@ -187,16 +212,20 @@ class Module(object):
app_id = self.bot.config["tfl-api-id"]
app_key = self.bot.config["tfl-api-key"]
#As awful as this is, it also makes it ~work~.
# As awful as this is, it also makes it ~work~.
stop_name = event["args"].replace(" ", "%20")
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:
for stop in stop_search["matches"]:
pass
results = ["%s (%s): %s" % (stop["name"], ", ".join(stop["modes"]), stop["id"]) for stop in stop_search["matches"]]
event["stdout"].write("[%s results] %s" % (stop_search["total"], "; ".join(results)))
results = ["%s (%s): %s" % (
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:
event["stderr"].write("No results")
@ -209,12 +238,16 @@ class Module(object):
vehicle = Utils.get_url(URL_VEHICLE % vehicle_id, get_params={
"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"])
event["stdout"].write("%s (%s) to %s. %s. Arrival at %s (%s) in %s minutes on %s" % (
vehicle["vehicleId"], vehicle["lineName"], vehicle["destinationName"], vehicle["currentLocation"],
vehicle["stationName"], vehicle["naptanId"], arrival_time, platform))
event["stdout"].write(
"%s (%s) to %s. %s. Arrival at %s (%s) in %s minutes on %s" % (
vehicle["vehicleId"], vehicle["lineName"],
vehicle["destinationName"], vehicle["currentLocation"],
vehicle["stationName"], vehicle["naptanId"], arrival_time,
platform))
def service(self, event):
app_id = self.bot.config["tfl-api-id"]
@ -228,19 +261,25 @@ class Module(object):
return
results = self.result_map[event["target"].id]
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
service = results[int(service_id)]
arrivals = Utils.get_url(URL_LINE_ARRIVALS % service["route"], get_params={
"app_id": app_id, "app_key": app_key}, json=True)
arrivals = Utils.get_url(URL_LINE_ARRIVALS % service["route"],
get_params={
"app_id": app_id, "app_key": app_key},
json=True)
arrivals = [a for a in arrivals if a["vehicleId"] == service["id"]]
arrivals = sorted(arrivals, key=lambda b: b["timeToStation"])
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)" %
(a["stationName"], self.platform(a.get("platformName", "?"), True),
(a["stationName"],
self.platform(a.get("platformName", "?"), True),
a["expectedArrival"][11:16]
) for a in arrivals]))

View file

@ -1,21 +1,24 @@
#--require-config bighugethesaurus-api-key
# --require-config bighugethesaurus-api-key
import Utils
URL_THESAURUS = "http://words.bighugelabs.com/api/2/%s/%s/json"
class Module(object):
def __init__(self, bot):
self.bot = bot
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",
usage="<word> [type]")
def thesaurus(self, event):
phrase = event["args_split"][0]
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]
if page:
if not len(event["args_split"]) > 1:

View file

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

View file

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

View file

@ -1,5 +1,3 @@
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -16,17 +14,21 @@ class Module(object):
def todo(self, event):
todo = event["user"].get_setting("todo", [])
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])
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:
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:
event["stderr"].write("Please provide a number")
else:
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):
arg_lower = event["args"].lower()
@ -45,11 +47,12 @@ class Module(object):
if event["args_split"][0].isdigit() and int(event["args_split"][0]) > 0:
index = int(event["args_split"][0])
if len(todo) >= index:
todo.pop(index-1)
todo.pop(index - 1)
event["user"].set_setting("todo", todo)
event["stdout"].write("Todo item removed")
else:
event["stderr"].write("You do not have that many things in "
"your todo")
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

@ -1,20 +1,23 @@
#--require-config trakt-api-key
# --require-config trakt-api-key
import Utils
URL_TRAKT = "https://api-v2launch.trakt.tv/users/%s/watching"
URL_TRAKTSLUG = "https://trakt.tv/%s/%s"
class Module(object):
def __init__(self, bot):
self.bot = bot
bot.events.on("received").on("command").on("nowwatching",
"nw").hook(self.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"
).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):
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"
REGEX_LANGUAGES = re.compile("(\w+)?:(\w+)? ")
class Module(object):
def __init__(self, bot):
bot.events.on("received").on("command").on("translate", "tr").hook(
@ -47,4 +48,3 @@ class Module(object):
else:
event["stderr"].write("Failed to translate, try checking "
"source/target languages (" + URL_LANGUAGES + ")")

View file

@ -1,7 +1,7 @@
#--require-config twitter-api-key
#--require-config twitter-api-secret
#--require-config twitter-access-token
#--require-config twitter-access-secret
# --require-config twitter-api-key
# --require-config twitter-api-secret
# --require-config twitter-access-token
# --require-config twitter-access-secret
import datetime, re, time, traceback
import twitter
@ -10,15 +10,17 @@ import Utils
REGEX_TWITTERURL = re.compile(
"https?://(?:www\.)?twitter.com/[^/]+/status/(\d+)", re.I)
class Module(object):
def __init__(self, bot):
self.bot = bot
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]")
def make_timestamp(self, s):
seconds_since = time.time()-datetime.datetime.strptime(s,
seconds_since = time.time() - datetime.datetime.strptime(s,
"%a %b %d %H:%M:%S %z %Y").timestamp()
since, unit = Utils.time_unit(seconds_since)
return "%s %s ago" % (since, unit)
@ -64,13 +66,17 @@ class Module(object):
retweet_timestamp = self.make_timestamp(tweet[
"created_at"])
original_timestamp = self.make_timestamp(tweet[
"retweeted_status"]["created_at"])
"retweeted_status"][
"created_at"])
event["stdout"].write("(%s (%s) retweeted %s (%s)) %s" % (
username, retweet_timestamp,
original_username, original_timestamp, original_text))
else:
event["stdout"].write("(%s, %s) %s" % (username,
self.make_timestamp(tweet["created_at"]), tweet["text"]))
self.make_timestamp(
tweet[
"created_at"]),
tweet["text"]))
else:
event["stderr"].write("Invalid tweet identifiers provided")
else:

View file

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

View file

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

View file

@ -1,9 +1,10 @@
#--require-config openweathermap-api-key
# --require-config openweathermap-api-key
import Utils
URL_WEATHER = "http://api.openweathermap.org/data/2.5/weather"
class Module(object):
def __init__(self, bot):
self.bot = bot
@ -23,7 +24,7 @@ class Module(object):
location = "%s, %s" % (page["name"], page["sys"][
"country"])
celsius = "%dC" % page["main"]["temp"]
fahrenheit = "%dF" % ((page["main"]["temp"]*(9/5))+32)
fahrenheit = "%dF" % ((page["main"]["temp"] * (9 / 5)) + 32)
description = page["weather"][0]["description"].title()
humidity = "%s%%" % page["main"]["humidity"]
wind_speed = "%sKM/h" % page["wind"]["speed"]
@ -33,6 +34,7 @@ class Module(object):
location, celsius, fahrenheit, description, humidity,
wind_speed))
else:
event["stderr"].write("No weather information for this location")
event["stderr"].write(
"No weather information for this location")
else:
event["stderr"].write("Failed to load results")

View file

@ -2,11 +2,13 @@ import Utils
URL_WIKIPEDIA = "https://en.wikipedia.org/w/api.php"
class Module(object):
def __init__(self, bot):
self.bot = bot
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):
page = Utils.get_url(URL_WIKIPEDIA, get_params={
@ -25,4 +27,3 @@ class Module(object):
event["stderr"].write("No results found")
else:
event["stderr"].write("Failed to load results")

View file

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

View file

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

View file

@ -1,4 +1,4 @@
#--require-config google-api-key
# --require-config google-api-key
import re
import Utils
@ -16,12 +16,14 @@ URL_YOUTUBESHORT = "https://youtu.be/%s"
ARROW_UP = ""
ARROW_DOWN = ""
class Module(object):
def __init__(self, bot):
self.bot = bot
bot.events.on("received").on("command").on("yt", "youtube"
).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(
self.channel_message)
@ -30,11 +32,14 @@ class Module(object):
help="Disable/Enable automatically getting info from youtube URLs",
validate=Utils.bool_or_none)
def get_video_page(self, video_id, 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)
def video_details(self, video_id):
snippet = self.get_video_page(video_id, "snippet")
if snippet["items"]:
@ -57,14 +62,18 @@ class Module(object):
match = re.match(REGEX_ISO8601, video_duration)
video_duration = ""
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
) if match.group(2) else "00:"
) if match.group(
2) else "00:"
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" % (
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):
video_id = None
@ -74,13 +83,17 @@ class Module(object):
else:
last_youtube = event["buffer"].find(REGEX_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 not video_id:
search_page = Utils.get_url(URL_YOUTUBESEARCH,
get_params={"q": search, "part": "snippet",
"maxResults": "1", "type": "video",
"key": self.bot.config["google-api-key"]},
get_params={"q": search,
"part": "snippet",
"maxResults": "1",
"type": "video",
"key": self.bot.config[
"google-api-key"]},
json=True)
if search_page:
if search_page["pageInfo"]["totalResults"] > 0:
@ -104,4 +117,5 @@ class Module(object):
if video_details:
self.bot.events.on("send").on("stdout").call(target=event[
"channel"], message=video_details, module_name="Youtube",
server=event["server"])
server=event[
"server"])