Updated for rewrite: Batch 2
This commit is contained in:
commit
a05b768274
10
bot.py
10
bot.py
|
@ -15,11 +15,9 @@ from cogs import utils
|
|||
opts = {'command_prefix': utils.command_prefix,
|
||||
'description': utils.bot_description,
|
||||
'pm_help': None,
|
||||
'shard_count': utils.shard_count,
|
||||
'shard_id': utils.shard_id,
|
||||
'command_not_found': ''}
|
||||
|
||||
bot = commands.Bot(**opts)
|
||||
bot = commands.AutoShardedBot(**opts)
|
||||
logging.basicConfig(level=logging.WARNING, filename='bonfire.log')
|
||||
|
||||
|
||||
|
@ -104,12 +102,12 @@ async def on_command_error(error, ctx):
|
|||
m, s = divmod(error.retry_after, 60)
|
||||
fmt = "This command is on cooldown! Hold your horses! >:c\nTry again in {} minutes and {} seconds" \
|
||||
.format(round(m), round(s))
|
||||
await bot.send_message(ctx.message.channel, fmt)
|
||||
await ctx.message.channel.send(fmt)
|
||||
elif isinstance(error, commands.NoPrivateMessage):
|
||||
fmt = "This command cannot be used in a private message"
|
||||
await bot.send_message(ctx.message.channel, fmt)
|
||||
await ctx.message.channel.send(fmt)
|
||||
elif isinstance(error, commands.MissingRequiredArgument):
|
||||
await bot.send_message(ctx.message.channel, error)
|
||||
await ctx.message.channel.send(error)
|
||||
else:
|
||||
now = datetime.datetime.now()
|
||||
with open("error_log", 'a') as f:
|
||||
|
|
|
@ -34,17 +34,17 @@ class Blackjack:
|
|||
# When we're done with the game, we need to delete the game itself and remove it's instance from games
|
||||
# To do this, it needs to be able to access this instance of Blackjack
|
||||
game = Game(self.bot, message, self)
|
||||
self.games[message.server.id] = game
|
||||
self.games[message.guild.id] = game
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, aliases=['bj'], invoke_without_command=True)
|
||||
@commands.group(no_pm=True, aliases=['bj'], invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def blackjack(self, ctx):
|
||||
"""Creates a game/joins the current running game of blackjack
|
||||
|
||||
EXAMPLE: !blackjack
|
||||
RESULT: A new game of blackjack!"""
|
||||
# Get this server's game if it exists
|
||||
game = self.games.get(ctx.message.server.id)
|
||||
# Get this guild's game if it exists
|
||||
game = self.games.get(ctx.message.guild.id)
|
||||
# If it doesn't, start one
|
||||
if game is None:
|
||||
self.create_game(ctx.message)
|
||||
|
@ -54,15 +54,15 @@ class Blackjack:
|
|||
# If it worked, they're ready to play
|
||||
if status:
|
||||
fmt = "{} has joined the game of blackjack, and will be able to play next round!"
|
||||
await self.bot.say(fmt.format(ctx.message.author.display_name))
|
||||
await ctx.send(fmt.format(ctx.message.author.display_name))
|
||||
else:
|
||||
# Otherwise, lets check *why* they couldn't join
|
||||
if game.playing(ctx.message.author):
|
||||
await self.bot.say("You are already playing! Wait for your turn!")
|
||||
await ctx.send("You are already playing! Wait for your turn!")
|
||||
else:
|
||||
await self.bot.say("There are already a max number of players playing/waiting to play!")
|
||||
await ctx.send("There are already a max number of players playing/waiting to play!")
|
||||
|
||||
@blackjack.command(pass_context=True, no_pm=True, name='leave', aliases=['quit'])
|
||||
@blackjack.command(no_pm=True, name='leave', aliases=['quit'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def blackjack_leave(self, ctx):
|
||||
"""Leaves the current game of blackjack
|
||||
|
@ -70,37 +70,37 @@ class Blackjack:
|
|||
EXAMPLE: !blackjack leave
|
||||
RESULT: You stop losing money in blackjack"""
|
||||
|
||||
# Get this server's game if it exists
|
||||
game = self.games.get(ctx.message.server.id)
|
||||
# Get this guild's game if it exists
|
||||
game = self.games.get(ctx.message.guild.id)
|
||||
|
||||
if game is None:
|
||||
await self.bot.say("There are currently no games of Blackjack running!")
|
||||
await ctx.send("There are currently no games of Blackjack running!")
|
||||
return
|
||||
|
||||
status = game.leave(ctx.message.author)
|
||||
if status:
|
||||
await self.bot.say("You have left the game, and will be removed at the end of this round")
|
||||
await ctx.send("You have left the game, and will be removed at the end of this round")
|
||||
else:
|
||||
await self.bot.say("Either you have already bet, or you are not even playing right now!")
|
||||
await ctx.send("Either you have already bet, or you are not even playing right now!")
|
||||
|
||||
@blackjack.command(pass_context=True, no_pm=True, name='forcestop', aliases=['stop'])
|
||||
@utils.custom_perms(manage_server=True)
|
||||
@blackjack.command(no_pm=True, name='forcestop', aliases=['stop'])
|
||||
@utils.custom_perms(manage_guild=True)
|
||||
async def blackjack_stop(self, ctx):
|
||||
"""Forces the game to stop, mostly for use if someone has gone afk
|
||||
|
||||
EXAMPLE: !blackjack forcestop
|
||||
RESULT: No more blackjack spam"""
|
||||
|
||||
# Get this server's game if it exists
|
||||
game = self.games.get(ctx.message.server.id)
|
||||
# Get this guild's game if it exists
|
||||
game = self.games.get(ctx.message.guild.id)
|
||||
|
||||
if game is None:
|
||||
await self.bot.say("There are currently no games of Blackjack running!")
|
||||
await ctx.send("There are currently no games of Blackjack running!")
|
||||
return
|
||||
|
||||
game.task.cancel()
|
||||
del self.games[ctx.message.server.id]
|
||||
await self.bot.say("The blackjack game running here has just ended")
|
||||
del self.games[ctx.message.guild.id]
|
||||
await ctx.send("The blackjack game running here has just ended")
|
||||
|
||||
|
||||
def FOIL(a, b):
|
||||
|
@ -226,7 +226,7 @@ class Game:
|
|||
async def game_task(self):
|
||||
"""The task to handle the entire game"""
|
||||
while len(self.players) > 0:
|
||||
await self.bot.send_message(self.channel, "A new round has started!!")
|
||||
await self.channel.send("A new round has started!!")
|
||||
|
||||
# First wait for bets
|
||||
await self.bet_task()
|
||||
|
@ -253,25 +253,25 @@ class Game:
|
|||
await self.cleanup()
|
||||
|
||||
# If we reach the end of this loop, that means there are no more players
|
||||
del self.bj.games[self.channel.server.id]
|
||||
del self.bj.games[self.channel.guild.id]
|
||||
|
||||
async def dealer_task(self):
|
||||
"""The task handling the dealer's play after all players have stood"""
|
||||
fmt = "It is the dealer's turn to play\n\n{}".format(self.dealer)
|
||||
msg = await self.bot.send_message(self.channel, fmt)
|
||||
msg = await self.channel.send(fmt)
|
||||
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
if self.dealer.bust:
|
||||
fmt = msg.content + "\n\nDealer has busted!!"
|
||||
await self.bot.edit_message(msg, fmt)
|
||||
await msg.edit(content=fmt)
|
||||
return
|
||||
for num in self.dealer.count:
|
||||
if num > 16:
|
||||
return
|
||||
self.hit(self.dealer)
|
||||
fmt = "It is the dealer's turn to play\n\n{}".format(self.dealer)
|
||||
msg = await self.bot.edit_message(msg, fmt)
|
||||
msg = await msg.edit(content=fmt)
|
||||
|
||||
async def round_task(self):
|
||||
"""The task handling the round itself, asking each person to hit or stand"""
|
||||
|
@ -280,21 +280,25 @@ class Game:
|
|||
# A differen task will handle if a player hit blackjack to start (so they would not be 'playing')
|
||||
|
||||
# Our check to make sure a valid 'command' was provided
|
||||
check = lambda m: m.content.lower() in ['hit', 'stand', 'double']
|
||||
def check(m):
|
||||
if m.channel == self.channel and m.author == player.member:
|
||||
return m.content.lower() in ['hit', 'stand', 'double']
|
||||
else:
|
||||
return False
|
||||
|
||||
# First lets handle the blackjacks
|
||||
for entry in [p for p in self.players if p['status'] == 'blackjack']:
|
||||
player = entry['player']
|
||||
fmt = "You got a blackjack {0.member.mention}!\n\n{0}".format(player)
|
||||
|
||||
await self.bot.send_message(self.channel, fmt)
|
||||
await self.channel.send(fmt)
|
||||
# Loop through each player (as long as their status is playing) and they have bet chips
|
||||
for entry in [p for p in self.players if p['status'] == 'playing' and hasattr(p['player'], 'bet')]:
|
||||
player = entry['player']
|
||||
|
||||
# Let them know it's their turn to play
|
||||
fmt = "It is your turn to play {0.member.mention}\n\n{0}".format(player)
|
||||
await self.bot.send_message(self.channel, fmt)
|
||||
await self.channel.send(fmt)
|
||||
|
||||
# If they're not playing anymore (i.e. they busted, are standing, etc.) then we don't want to keep asking
|
||||
# them to hit or stand
|
||||
|
@ -302,37 +306,28 @@ class Game:
|
|||
|
||||
# Ask if they want to hit or stand
|
||||
fmt = "Hit, stand, or double?"
|
||||
await self.bot.send_message(self.channel, fmt)
|
||||
msg = await self.bot.wait_for_message(timeout=60, author=player.member, channel=self.channel,
|
||||
check=check)
|
||||
await self.channel.send(fmt)
|
||||
|
||||
# If they took to long, make them stand so the next person can play
|
||||
if msg is None:
|
||||
await self.bot.send_message(self.channel, "Took to long! You're standing!")
|
||||
try:
|
||||
msg = await self.bot.wait_for('message', timeout=60, check=check)
|
||||
except asyncio.TimeoutError:
|
||||
await self.channel.send("Took to long! You're standing!")
|
||||
entry['status'] = 'stand'
|
||||
# If they want to hit
|
||||
elif 'hit' in msg.content.lower():
|
||||
self.hit(player)
|
||||
await self.bot.send_message(self.channel, player)
|
||||
# If they want to stand
|
||||
elif 'stand' in msg.content.lower():
|
||||
self.stand(player)
|
||||
elif 'double' in msg.content.lower():
|
||||
self.double(player)
|
||||
await self.bot.send_message(self.channel, player)
|
||||
# TODO: Handle double, split
|
||||
else:
|
||||
# If they want to hit
|
||||
if 'hit' in msg.content.lower():
|
||||
self.hit(player)
|
||||
await self.channel.send(player)
|
||||
# If they want to stand
|
||||
elif 'stand' in msg.content.lower():
|
||||
self.stand(player)
|
||||
elif 'double' in msg.content.lower():
|
||||
self.double(player)
|
||||
await self.channel.send(player)
|
||||
# TODO: Handle double, split
|
||||
|
||||
async def bet_task(self):
|
||||
"""Performs the task of betting"""
|
||||
|
||||
def check(_msg):
|
||||
"""Makes sure the message provided is within the min and max bets"""
|
||||
try:
|
||||
msg_length = int(_msg.content)
|
||||
return self.min_bet <= msg_length <= self.max_bet
|
||||
except ValueError:
|
||||
return _msg.content.lower() == 'skip'
|
||||
|
||||
# There is one situation that we want to allow that means we cannot loop through players like normally would
|
||||
# be the case: Betting has started; while one person is betting, another joins This means our list has
|
||||
# changed, and neither based on the length or looping through the list itself will handle this To handle
|
||||
|
@ -348,28 +343,43 @@ class Game:
|
|||
entry = players[0]
|
||||
player = entry['player']
|
||||
|
||||
def check(_msg):
|
||||
"""Makes sure the message provided is within the min and max bets"""
|
||||
if _msg.channel == self.channel and _msg.author == player.member:
|
||||
try:
|
||||
msg_length = int(_msg.content)
|
||||
return self.min_bet <= msg_length <= self.max_bet
|
||||
except ValueError:
|
||||
return _msg.content.lower() == 'skip'
|
||||
else:
|
||||
return False
|
||||
|
||||
fmt = "Your turn to bet {0.member.mention}, your current chips are: {0.chips}\n" \
|
||||
"Current min bet is {1}, current max bet is {2}\n" \
|
||||
"Place your bet now (please provide only the number;" \
|
||||
"'skip' if you would like to leave this game)".format(player, self.min_bet, self.max_bet)
|
||||
await self.bot.send_message(self.channel, fmt)
|
||||
msg = await self.bot.wait_for_message(timeout=60, author=player.member, channel=self.channel, check=check)
|
||||
|
||||
if msg is None:
|
||||
await self.bot.send_message(self.channel, "You took too long! You're sitting this round out")
|
||||
await self.channel.send(fmt)
|
||||
|
||||
try:
|
||||
msg = await self.bot.wait_for("message", timeout=60, check=check)
|
||||
except asyncio.TimeoutError:
|
||||
await self.channel.send("You took too long! You're sitting this round out")
|
||||
entry['status'] = 'stand'
|
||||
elif msg.content.lower() == 'skip':
|
||||
await self.bot.send_message(self.channel, "Alright, you've been removed from the game")
|
||||
self.leave(player.member)
|
||||
else:
|
||||
num = int(msg.content)
|
||||
# Set the new bet, and remove it from this players chip total
|
||||
if num <= player.chips:
|
||||
player.bet = num
|
||||
player.chips -= num
|
||||
entry['status'] = 'bet'
|
||||
if msg.content.lower() == 'skip':
|
||||
await self.channel.send("Alright, you've been removed from the game")
|
||||
self.leave(player.member)
|
||||
else:
|
||||
await self.bot.send_message(self.channel, "You can't bet more than you have!!")
|
||||
num = int(msg.content)
|
||||
# Set the new bet, and remove it from this players chip total
|
||||
if num <= player.chips:
|
||||
player.bet = num
|
||||
player.chips -= num
|
||||
entry['status'] = 'bet'
|
||||
else:
|
||||
await self.channel.send("You can't bet more than you have!!")
|
||||
|
||||
# Call this so that we can correct the list, if someone has left or join
|
||||
self.player_cleanup()
|
||||
|
||||
|
@ -464,7 +474,7 @@ class Game:
|
|||
# Add that to the main string
|
||||
fmt += "Blackjacks: {}\n".format(_fmt)
|
||||
|
||||
await self.bot.send_message(self.channel, fmt)
|
||||
await self.channel.send(fmt)
|
||||
|
||||
# Do the same for the dealers hand
|
||||
cards = list(self.dealer.hand.draw(self.dealer.hand.count))
|
||||
|
@ -481,10 +491,10 @@ class Game:
|
|||
self.players.extend(self._added_players)
|
||||
self._added_players.clear()
|
||||
|
||||
# What we want to do is remove any players that are in the game and have left the server
|
||||
# What we want to do is remove any players that are in the game and have left the guild
|
||||
for entry in self.players:
|
||||
m = entry['player'].member
|
||||
if m not in self.channel.server.members:
|
||||
if m not in self.channel.guild.members:
|
||||
self._removed_players.append(entry['player'])
|
||||
|
||||
# Remove the players who left
|
||||
|
|
|
@ -10,7 +10,7 @@ from enum import Enum
|
|||
class Chess:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
# Our format for games is going to be a little different, because we do want to allow multiple games per server
|
||||
# Our format for games is going to be a little different, because we do want to allow multiple games per guild
|
||||
# Format should be {'server_id': [Game, Game, Game]}
|
||||
self.games = {}
|
||||
|
||||
|
@ -91,18 +91,18 @@ class Chess:
|
|||
return MoveStatus.invalid
|
||||
|
||||
def get_game(self, player):
|
||||
"""Provides the game this player is playing, in this server"""
|
||||
server_games = self.games.get(player.server.id, [])
|
||||
for game in server_games:
|
||||
"""Provides the game this player is playing, in this guild"""
|
||||
guild_games = self.games.get(player.guild.id, [])
|
||||
for game in guild_games:
|
||||
if player in game.challengers.values():
|
||||
return game
|
||||
|
||||
return None
|
||||
|
||||
def in_game(self, player):
|
||||
"""Checks to see if a player is playing in a game right now, in this server"""
|
||||
server_games = self.games.get(player.server.id, [])
|
||||
for game in server_games:
|
||||
"""Checks to see if a player is playing in a game right now, in this guild"""
|
||||
guild_games = self.games.get(player.guild.id, [])
|
||||
for game in guild_games:
|
||||
if player in game.challengers.values():
|
||||
return True
|
||||
|
||||
|
@ -111,13 +111,13 @@ class Chess:
|
|||
def start_game(self, player1, player2):
|
||||
game = Game(player1, player2)
|
||||
try:
|
||||
self.games[player1.server.id].append(game)
|
||||
self.games[player1.guild.id].append(game)
|
||||
except KeyError:
|
||||
self.games[player1.server.id] = [game]
|
||||
self.games[player1.guild.id] = [game]
|
||||
|
||||
return game
|
||||
|
||||
@commands.group(pass_contxt=True, invoke_without_command=True)
|
||||
@commands.group(invoke_without_command=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def chess(self, ctx, *, move):
|
||||
"""Moves a piece based on the notation provided
|
||||
|
@ -142,47 +142,48 @@ class Chess:
|
|||
EXAMPLE: !rook to d4"""
|
||||
result = self.play(ctx.message.author, move)
|
||||
if result is MoveStatus.invalid:
|
||||
await self.bot.say("That was an invalid move!")
|
||||
await ctx.send("That was an invalid move!")
|
||||
elif result is MoveStatus.wrong_turn:
|
||||
await self.bot.say("It is not your turn to play on your game in this server!")
|
||||
await ctx.send("It is not your turn to play on your game in this guild!")
|
||||
elif result is MoveStatus.no_game:
|
||||
await self.bot.say("You are not currently playing a game on this server!")
|
||||
await ctx.send("You are not currently playing a game on this guild!")
|
||||
elif result is MoveStatus.valid:
|
||||
game = self.get_game(ctx.message.author)
|
||||
link = game.draw_board()
|
||||
await self.bot.upload(link)
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def chess_start(self, ctx, player2: discord.Member):
|
||||
"""Starts a chess game with another player
|
||||
You can play one game on a single server at a time
|
||||
You can play one game on a single guild at a time
|
||||
|
||||
EXAMPLE: !chess start @Victim
|
||||
RESULT: A new chess game! Good luck~"""
|
||||
|
||||
# Lets first check our permissions; we're not going to create a text based board
|
||||
# So we need to be able to attach files in order to send the board
|
||||
if not ctx.message.channel.permissions_for(ctx.message.server.me).attach_files:
|
||||
await self.bot.say(
|
||||
if not ctx.message.channel.permissions_for(ctx.message.guild.me).attach_files:
|
||||
await ctx.send(
|
||||
"I need to be able to send pictures to provide the board! Please ask someone with mange roles permission, to grant me attach files permission if you want to play this")
|
||||
return
|
||||
|
||||
# Make sure the author and player 2 are not in a game already
|
||||
if self.in_game(ctx.message.author):
|
||||
await self.bot.say("Sorry, but you can only be in one game per server at a time")
|
||||
await ctx.send("Sorry, but you can only be in one game per guild at a time")
|
||||
return
|
||||
|
||||
if self.in_game(player2):
|
||||
await self.bot.say("Sorry, but {} is already in a game on this server!".format(player2.display_name))
|
||||
await ctx.send("Sorry, but {} is already in a game on this guild!".format(player2.display_name))
|
||||
return
|
||||
|
||||
# Start the game
|
||||
game = self.start_game(ctx.message.author, player2)
|
||||
player1 = game.challengers.get('white')
|
||||
await self.bot.say(
|
||||
"{} you have started a chess game with {}\n\n{} will be white this game, and is going first.\nIf you need information about the notation used to play, run {}help chess".format(
|
||||
ctx.message.author.display_name, player2.display_name, ctx.prefix))
|
||||
await ctx.send(
|
||||
"{} you have started a chess game with {}\n\n{} will be white this game, and is going first.\nIf you need "
|
||||
"information about the notation used to play, run {}help chess".format(
|
||||
ctx.message.author.display_name, player2.display_name, player1, ctx.prefix))
|
||||
|
||||
|
||||
class MoveStatus(Enum):
|
||||
|
@ -209,7 +210,7 @@ class Game:
|
|||
self.reset_board()
|
||||
|
||||
# The point of chess revolves around the king's position
|
||||
# Due to this, we're going to use the king's position a lot, so lets save this variable
|
||||
# Due to this, we're going to use the king's position a lot, so lets save this variable
|
||||
self.w_king_pos = (0, 4)
|
||||
self.b_king_pos = (7, 4)
|
||||
|
||||
|
@ -262,7 +263,7 @@ class Game:
|
|||
colour = 'black'
|
||||
king_pos = self.b_king_pos
|
||||
|
||||
if not can_castle[colour][pos]:
|
||||
if not self.can_castle[colour][pos]:
|
||||
return False
|
||||
|
||||
# During castling, the row should never change
|
||||
|
@ -388,7 +389,7 @@ class Game:
|
|||
def check(self):
|
||||
"""Checks our current board, and checks (based on whose turn it is) if we're in a 'check' state"""
|
||||
# To check for a check, what we should do is loop through the board
|
||||
# Then check if it's the the current players turn's piece, and compare to moving to the king's position
|
||||
# Then check if it's the the current players turn's piece, and compare to moving to the king's position
|
||||
for x, row in enumerate(self.board):
|
||||
for y, piece in enumerate(row):
|
||||
if self.white_turn and re.search('B.', piece) and self.valid_move((x, y), self.b_king_pos):
|
||||
|
|
105
cogs/core.py
105
cogs/core.py
|
@ -10,7 +10,6 @@ import re
|
|||
import calendar
|
||||
import pendulum
|
||||
import datetime
|
||||
import math
|
||||
|
||||
|
||||
class Core:
|
||||
|
@ -23,30 +22,7 @@ class Core:
|
|||
self.results_per_page = 10
|
||||
self.commands = None
|
||||
|
||||
def find_command(self, command):
|
||||
# This method ensures the command given is valid. We need to loop through commands
|
||||
# As self.bot.commands only includes parent commands
|
||||
# So we are splitting the command in parts, looping through the commands
|
||||
# And getting the subcommand based on the next part
|
||||
# If we try to access commands of a command that isn't a group
|
||||
# We'll hit an AttributeError, meaning an invalid command was given
|
||||
# If we loop through and don't find anything, cmd will still be None
|
||||
# And we'll report an invalid was given as well
|
||||
cmd = None
|
||||
|
||||
for part in command.split():
|
||||
try:
|
||||
if cmd is None:
|
||||
cmd = self.bot.commands.get(part)
|
||||
else:
|
||||
cmd = cmd.commands.get(part)
|
||||
except AttributeError:
|
||||
cmd = None
|
||||
break
|
||||
|
||||
return cmd
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def help(self, ctx, *, message=None):
|
||||
"""This command is used to provide a link to the help URL.
|
||||
|
@ -65,7 +41,7 @@ class Core:
|
|||
try:
|
||||
page = int(message)
|
||||
except:
|
||||
cmd = self.find_command(message)
|
||||
cmd = self.bot.get_command(message)
|
||||
|
||||
if cmd is None:
|
||||
entries = sorted(utils.get_all_commands(self.bot))
|
||||
|
@ -73,7 +49,7 @@ class Core:
|
|||
pages = utils.Pages(self.bot, message=ctx.message, entries=entries)
|
||||
await pages.paginate(start_page=page)
|
||||
except utils.CannotPaginate as e:
|
||||
await self.bot.say(str(e))
|
||||
await ctx.send(str(e))
|
||||
else:
|
||||
# Get the description for a command
|
||||
description = cmd.help
|
||||
|
@ -100,11 +76,11 @@ class Core:
|
|||
if subcommands:
|
||||
embed.add_field(name='Subcommands', value="\n".join(subcommands), inline=False)
|
||||
|
||||
await self.bot.say(embed=embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def motd(self, *, date=None):
|
||||
async def motd(self, ctx, *, date=None):
|
||||
"""This command can be used to print the current MOTD (Message of the day)
|
||||
This will most likely not be updated every day, however messages will still be pushed to this every now and then
|
||||
|
||||
|
@ -126,10 +102,10 @@ class Core:
|
|||
motd = latest_motd['motd']
|
||||
# This will be hit if we do not have any entries for motd
|
||||
except TypeError:
|
||||
await self.bot.say("No message of the day!")
|
||||
await ctx.send("No message of the day!")
|
||||
else:
|
||||
fmt = "Last updated: {}\n\n{}".format(date, motd)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
else:
|
||||
try:
|
||||
r_filter = pendulum.parse(date)
|
||||
|
@ -137,18 +113,18 @@ class Core:
|
|||
date = motd[0]['date']
|
||||
motd = motd[0]['motd']
|
||||
fmt = "Message of the day for {}:\n\n{}".format(date, motd)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
# This one will be hit if we return None for that day
|
||||
except TypeError:
|
||||
await self.bot.say("No message of the day for {}!".format(date))
|
||||
await ctx.send("No message of the day for {}!".format(date))
|
||||
# This will be hit if pendulum fails to parse the date passed
|
||||
except ValueError:
|
||||
now = pendulum.utcnow().to_date_string()
|
||||
await self.bot.say("Invalid date format! Try like {}".format(now))
|
||||
await ctx.send("Invalid date format! Try like {}".format(now))
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def calendar(self, month: str = None, year: int = None):
|
||||
async def calendar(self, ctx, month: str = None, year: int = None):
|
||||
"""Provides a printout of the current month's calendar
|
||||
Provide month and year to print the calendar of that year and month
|
||||
|
||||
|
@ -176,30 +152,23 @@ class Core:
|
|||
else:
|
||||
month = months.get(month.lower())
|
||||
if month is None:
|
||||
await self.bot.say("Please provide a valid Month!")
|
||||
await ctx.send("Please provide a valid Month!")
|
||||
return
|
||||
# If year was not passed, use the current year
|
||||
if year is None:
|
||||
year = datetime.datetime.today().year
|
||||
# Here we create the actual "text" calendar that we are printing
|
||||
cal = calendar.TextCalendar().formatmonth(year, month)
|
||||
await self.bot.say("```\n{}```".format(cal))
|
||||
await ctx.send("```\n{}```".format(cal))
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def info(self):
|
||||
async def info(self, ctx):
|
||||
"""This command can be used to print out some of my information"""
|
||||
# fmt is a dictionary so we can set the key to it's output, then print both
|
||||
# The only real use of doing it this way is easier editing if the info
|
||||
# in this command is changed
|
||||
|
||||
bot_data = await utils.get_content('bot_data')
|
||||
total_data = {'member_count': 0,
|
||||
'server_count': 0}
|
||||
for entry in bot_data:
|
||||
total_data['member_count'] += entry['member_count']
|
||||
total_data['server_count'] += entry['server_count']
|
||||
|
||||
# Create the original embed object
|
||||
opts = {'title': 'Dev Server',
|
||||
'description': 'Join the server above for any questions/suggestions about me.',
|
||||
|
@ -207,8 +176,8 @@ class Core:
|
|||
embed = discord.Embed(**opts)
|
||||
|
||||
# Add the normal values
|
||||
embed.add_field(name='Total Servers', value=total_data['server_count'])
|
||||
embed.add_field(name='Total Members', value=total_data['member_count'])
|
||||
embed.add_field(name='Total Servers', value=len(self.bot.servers))
|
||||
embed.add_field(name='Total Members', value=len(set(self.bot.get_all_members())))
|
||||
|
||||
# Count the variable values; hangman, tictactoe, etc.
|
||||
hm_games = len(self.bot.get_cog('Hangman').games)
|
||||
|
@ -233,20 +202,20 @@ class Core:
|
|||
embed.add_field(name='Uptime', value=(pendulum.utcnow() - self.bot.uptime).in_words())
|
||||
embed.set_footer(text=self.bot.description)
|
||||
|
||||
await self.bot.say(embed=embed)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def uptime(self):
|
||||
async def uptime(self, ctx):
|
||||
"""Provides a printout of the current bot's uptime
|
||||
|
||||
EXAMPLE: !uptime
|
||||
RESULT: A BAJILLION DAYS"""
|
||||
await self.bot.say("Uptime: ```\n{}```".format((pendulum.utcnow() - self.bot.uptime).in_words()))
|
||||
await ctx.send("Uptime: ```\n{}```".format((pendulum.utcnow() - self.bot.uptime).in_words()))
|
||||
|
||||
@commands.command(aliases=['invite'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def addbot(self):
|
||||
async def addbot(self, ctx):
|
||||
"""Provides a link that you can use to add me to a server
|
||||
|
||||
EXAMPLE: !addbot
|
||||
|
@ -261,13 +230,17 @@ class Core:
|
|||
perms.embed_links = True
|
||||
perms.read_message_history = True
|
||||
perms.attach_files = True
|
||||
perms.speak = True
|
||||
perms.connect = True
|
||||
perms.attach_files = True
|
||||
perms.add_reactions = True
|
||||
app_info = await self.bot.application_info()
|
||||
await self.bot.say("Use this URL to add me to a server that you'd like!\n{}"
|
||||
.format(discord.utils.oauth_url(app_info.id, perms)))
|
||||
await ctx.send("Use this URL to add me to a server that you'd like!\n{}"
|
||||
.format(discord.utils.oauth_url(app_info.id, perms)))
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def doggo(self):
|
||||
async def doggo(self, ctx):
|
||||
"""Use this to print a random doggo image.
|
||||
|
||||
EXAMPLE: !doggo
|
||||
|
@ -275,11 +248,11 @@ class Core:
|
|||
# Find a random image based on how many we currently have
|
||||
f = random.SystemRandom().choice(glob.glob('images/doggo*'))
|
||||
with open(f, 'rb') as f:
|
||||
await self.bot.upload(f)
|
||||
await ctx.send(file=f)
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def snek(self):
|
||||
async def snek(self, ctx):
|
||||
"""Use this to print a random snek image.
|
||||
|
||||
EXAMPLE: !snek
|
||||
|
@ -287,11 +260,11 @@ class Core:
|
|||
# Find a random image based on how many we currently have
|
||||
f = random.SystemRandom().choice(glob.glob('images/snek*'))
|
||||
with open(f, 'rb') as f:
|
||||
await self.bot.upload(f)
|
||||
await ctx.send(file=f)
|
||||
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def joke(self):
|
||||
async def joke(self, ctx):
|
||||
"""Prints a random riddle
|
||||
|
||||
EXAMPLE: !joke
|
||||
|
@ -302,13 +275,13 @@ class Core:
|
|||
try:
|
||||
fortune = subprocess.check_output(
|
||||
fortune_command.split()).decode("utf-8")
|
||||
await self.bot.say(fortune)
|
||||
await ctx.send(fortune)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def roll(self, ctx, notation: str = "d6"):
|
||||
"""Rolls a die based on the notation given
|
||||
|
@ -325,7 +298,7 @@ class Core:
|
|||
# Check if something like ed3 was provided, or something else entirely
|
||||
# was provided
|
||||
except (AttributeError, ValueError):
|
||||
await self.bot.say("Please provide the die notation in #d#!")
|
||||
await ctx.send("Please provide the die notation in #d#!")
|
||||
return
|
||||
|
||||
# Dice will be None if d# was provided, assume this means 1d#
|
||||
|
@ -334,16 +307,16 @@ class Core:
|
|||
# have it set
|
||||
dice = int(dice)
|
||||
if dice > 10:
|
||||
await self.bot.say("I'm not rolling more than 10 dice, I have tiny hands")
|
||||
await ctx.send("I'm not rolling more than 10 dice, I have tiny hands")
|
||||
return
|
||||
if num > 100:
|
||||
await self.bot.say("What die has more than 100 sides? Please, calm down")
|
||||
await ctx.send("What die has more than 100 sides? Please, calm down")
|
||||
return
|
||||
if num <= 1:
|
||||
await self.bot.say("A {} sided die? You know that's impossible right?".format(num))
|
||||
await ctx.send("A {} sided die? You know that's impossible right?".format(num))
|
||||
return
|
||||
|
||||
nums = [random.SystemRandom().randint(1, num) for i in range(0, int(dice))]
|
||||
nums = [random.SystemRandom().randint(1, num) for _ in range(0, int(dice))]
|
||||
total = sum(nums)
|
||||
value_str = ", ".join("{}".format(x) for x in nums)
|
||||
|
||||
|
@ -351,7 +324,7 @@ class Core:
|
|||
fmt = '{0.message.author.name} has rolled a {2} sided die and got the number {3}!'
|
||||
else:
|
||||
fmt = '{0.message.author.name} has rolled {1}, {2} sided dice and got the numbers {3}, for a total of {4}!'
|
||||
await self.bot.say(fmt.format(ctx, dice, num, value_str, total))
|
||||
await ctx.send(fmt.format(ctx, dice, num, value_str, total))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
28
cogs/da.py
28
cogs/da.py
|
@ -59,9 +59,7 @@ class Deviantart:
|
|||
try:
|
||||
for entry in content:
|
||||
user = discord.utils.get(self.bot.get_all_members(), id=entry['member_id'])
|
||||
|
||||
# If we're sharded, we might not be able to find this user.
|
||||
# If the bot is not in the server with the member either
|
||||
# If the bot is not in the server with the member, we might not be able to find this user.
|
||||
if user is None:
|
||||
continue
|
||||
|
||||
|
@ -94,10 +92,10 @@ class Deviantart:
|
|||
if last_updated_id is not None:
|
||||
fmt = "There has been a new post by an artist you are subscribed to!\n\n" \
|
||||
"**Title:** {}\n**User:** {}\n**URL:** {}".format(
|
||||
result['title'],
|
||||
result['author']['username'],
|
||||
result['url'])
|
||||
await self.bot.send_message(user, fmt)
|
||||
result['title'],
|
||||
result['author']['username'],
|
||||
result['url'])
|
||||
await user.send(fmt)
|
||||
# Now we can update the user's last updated for this DA
|
||||
# We want to do this whether or not our last if statement was met
|
||||
r_filter = {'member_id': user.id}
|
||||
|
@ -110,12 +108,12 @@ class Deviantart:
|
|||
|
||||
@commands.group()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def da(self):
|
||||
async def da(self, ctx):
|
||||
"""This provides a sort of 'RSS' feed for subscribed to artists.
|
||||
Subscribe to artists, and I will PM you when new posts come out from these artists"""
|
||||
pass
|
||||
|
||||
@da.command(pass_context=True, name='sub', aliases=['add', 'subscribe'])
|
||||
@da.command(name='sub', aliases=['add', 'subscribe'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def da_sub(self, ctx, *, username):
|
||||
"""This can be used to add a feed to your notifications.
|
||||
|
@ -130,7 +128,7 @@ class Deviantart:
|
|||
if content is None:
|
||||
entry = {'member_id': ctx.message.author.id, 'subbed': [username], 'last_updated': {}}
|
||||
await utils.add_content('deviantart', entry, r_filter)
|
||||
await self.bot.say("You have just subscribed to {}!".format(username))
|
||||
await ctx.send("You have just subscribed to {}!".format(username))
|
||||
elif content[0]['subbed'] is None or username not in content[0]['subbed']:
|
||||
if content[0]['subbed'] is None:
|
||||
sub_list = [username]
|
||||
|
@ -138,9 +136,9 @@ class Deviantart:
|
|||
content[0]['subbed'].append(username)
|
||||
sub_list = content[0]['subbed']
|
||||
await utils.update_content('deviantart', {'subbed': sub_list}, r_filter)
|
||||
await self.bot.say("You have just subscribed to {}!".format(username))
|
||||
await ctx.send("You have just subscribed to {}!".format(username))
|
||||
else:
|
||||
await self.bot.say("You are already subscribed to that user!")
|
||||
await ctx.send("You are already subscribed to that user!")
|
||||
|
||||
@da.command(pass_context=True, name='unsub', aliases=['delete', 'remove', 'unsubscribe'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
|
@ -153,13 +151,13 @@ class Deviantart:
|
|||
content = await utils.get_content('deviantart', r_filter)
|
||||
|
||||
if content is None or content[0]['subbed'] is None:
|
||||
await self.bot.say("You are not subscribed to anyone at the moment!")
|
||||
await ctx.send("You are not subscribed to anyone at the moment!")
|
||||
elif username in content[0]['subbed']:
|
||||
content[0]['subbed'].remove(username)
|
||||
await utils.update_content('deviantart', {'subbed': content[0]['subbed']}, r_filter)
|
||||
await self.bot.say("You have just unsubscribed from {}!".format(username))
|
||||
await ctx.send("You have just unsubscribed from {}!".format(username))
|
||||
else:
|
||||
await self.bot.say("You are not subscribed to that user!")
|
||||
await ctx.send("You are not subscribed to that user!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -19,7 +19,7 @@ class Music:
|
|||
async def on_voice_state_update(self, before, after):
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def progress(self, ctx):
|
||||
"""Provides the progress of the current song
|
||||
|
@ -28,7 +28,7 @@ class Music:
|
|||
RESULT: 532 minutes! (Hopefully not)"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def join(self, ctx, *, channel: discord.Channel):
|
||||
"""Joins a voice channel.
|
||||
|
@ -37,7 +37,7 @@ class Music:
|
|||
RESULT: I'm in the Music voice channel!"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def summon(self, ctx):
|
||||
"""Summons the bot to join your voice channel.
|
||||
|
@ -46,7 +46,7 @@ class Music:
|
|||
RESULT: I'm in your voice channel!"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def play(self, ctx, *, song: str):
|
||||
"""Plays a song.
|
||||
|
@ -61,7 +61,7 @@ class Music:
|
|||
"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def volume(self, ctx, value: int = None):
|
||||
"""Sets the volume of the currently playing song.
|
||||
|
@ -70,7 +70,7 @@ class Music:
|
|||
RESULT: My volume is now set to 50"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def pause(self, ctx):
|
||||
"""Pauses the currently played song.
|
||||
|
@ -79,7 +79,7 @@ class Music:
|
|||
RESULT: I'm paused!"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def resume(self, ctx):
|
||||
"""Resumes the currently played song.
|
||||
|
@ -88,7 +88,7 @@ class Music:
|
|||
RESULT: Ain't paused no more!"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def stop(self, ctx):
|
||||
"""Stops playing audio and leaves the voice channel.
|
||||
|
@ -98,7 +98,7 @@ class Music:
|
|||
RESULT: No more music"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def eta(self, ctx):
|
||||
"""Provides an ETA on when your next song will play
|
||||
|
@ -107,7 +107,7 @@ class Music:
|
|||
RESULT: 5,000 days! Lol have fun"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def queue(self, ctx):
|
||||
"""Provides a printout of the songs that are in the queue.
|
||||
|
@ -121,7 +121,7 @@ class Music:
|
|||
RESULT: A list of shitty songs you probably don't wanna listen to"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def queuelength(self, ctx):
|
||||
"""Prints the length of the queue
|
||||
|
@ -130,7 +130,7 @@ class Music:
|
|||
RESULT: Probably 10 songs"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def skip(self, ctx):
|
||||
"""Vote to skip a song. The song requester can automatically skip.
|
||||
|
@ -142,7 +142,7 @@ class Music:
|
|||
"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def modskip(self, ctx):
|
||||
"""Forces a song skip, can only be used by a moderator
|
||||
|
@ -151,7 +151,7 @@ class Music:
|
|||
RESULT: No more terrible song :D"""
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, enabled=False)
|
||||
@commands.command(no_pm=True, enabled=False)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def playing(self, ctx):
|
||||
"""Shows info about the currently played song.
|
||||
|
|
|
@ -48,38 +48,17 @@ class StatsUpdate:
|
|||
log.info('bots.discord.pw statistics returned {} for {}'.format(resp.status, payload))
|
||||
|
||||
async def on_server_join(self, server):
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
entry = {'server_count': server_count, 'member_count': member_count, "shard_id": config.shard_id}
|
||||
# Check if this was successful, if it wasn't, that means a new shard was added and we need to add that entry
|
||||
if not await config.update_content('bot_data', entry, r_filter):
|
||||
await config.add_content('bot_data', entry, r_filter)
|
||||
self.bot.loop.create_task(self.update())
|
||||
|
||||
async def on_server_leave(self, server):
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
entry = {'server_count': server_count, 'member_count': member_count, "shard_id": config.shard_id}
|
||||
# Check if this was successful, if it wasn't, that means a new shard was added and we need to add that entry
|
||||
if not await config.update_content('bot_data', entry, r_filter):
|
||||
await config.add_content('bot_data', entry, r_filter)
|
||||
self.bot.loop.create_task(self.update())
|
||||
|
||||
async def on_ready(self):
|
||||
r_filter = {'shard_id': config.shard_id}
|
||||
server_count = len(self.bot.servers)
|
||||
member_count = len(set(self.bot.get_all_members()))
|
||||
entry = {'server_count': server_count, 'member_count': member_count, "shard_id": config.shard_id}
|
||||
# Check if this was successful, if it wasn't, that means a new shard was added and we need to add that entry
|
||||
if not await config.update_content('bot_data', entry, r_filter):
|
||||
await config.add_content('bot_data', entry, r_filter)
|
||||
self.bot.loop.create_task(self.update())
|
||||
|
||||
async def on_member_join(self, member):
|
||||
server = member.server
|
||||
r_filter = {'server_id': server.id}
|
||||
guild = member.guild
|
||||
r_filter = {'server_id': guild.id}
|
||||
notifications = await config.get_content('user_notifications', r_filter)
|
||||
|
||||
try:
|
||||
|
@ -91,12 +70,12 @@ class StatsUpdate:
|
|||
if not channel_id:
|
||||
return
|
||||
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel, "Welcome to the '{0.server.name}' server {0.mention}!".format(member))
|
||||
channel = guild.get_channel(channel_id)
|
||||
await channel.send("Welcome to the '{0.server.name}' server {0.mention}!".format(member))
|
||||
|
||||
async def on_member_remove(self, member):
|
||||
server = member.server
|
||||
r_filter = {'server_id': server.id}
|
||||
guild = member.guild
|
||||
r_filter = {'server_id': guild.id}
|
||||
notifications = await config.get_content('user_notifications', r_filter)
|
||||
|
||||
try:
|
||||
|
@ -109,9 +88,7 @@ class StatsUpdate:
|
|||
return
|
||||
|
||||
channel = server.get_channel(channel_id)
|
||||
await self.bot.send_message(channel,
|
||||
"{0} has left the server, I hope it wasn't because of something I said :c".format(
|
||||
member.display_name))
|
||||
await channelsend("{0} has left the server, I hope it wasn't because of something I said :c".format(member.display_name))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -104,10 +104,10 @@ class Hangman:
|
|||
def create(self, word, ctx):
|
||||
# Create a new game, then save it as the server's game
|
||||
game = Game(word)
|
||||
self.games[ctx.message.server.id] = game
|
||||
self.games[ctx.message.guild.id] = game
|
||||
return game
|
||||
|
||||
@commands.group(aliases=['hm'], pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@commands.group(aliases=['hm'], no_pm=True, invoke_without_command=True)
|
||||
@commands.cooldown(1, 7, BucketType.user)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def hangman(self, ctx, *, guess):
|
||||
|
@ -115,10 +115,10 @@ class Hangman:
|
|||
|
||||
EXAMPLE: !hangman e (or) !hangman The Phrase!
|
||||
RESULT: Hopefully a win!"""
|
||||
game = self.games.get(ctx.message.server.id)
|
||||
game = self.games.get(ctx.message.guild.id)
|
||||
if not game:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("There are currently no hangman games running!")
|
||||
await ctx.send("There are currently no hangman games running!")
|
||||
return
|
||||
|
||||
# Check if we are guessing a letter or a phrase. Only one letter can be guessed at a time
|
||||
|
@ -128,7 +128,7 @@ class Hangman:
|
|||
if len(guess) == 1:
|
||||
if guess in game.guessed_letters:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("That letter has already been guessed!")
|
||||
await ctx.send("That letter has already been guessed!")
|
||||
# Return here as we don't want to count this as a failure
|
||||
return
|
||||
if game.guess_letter(guess):
|
||||
|
@ -143,16 +143,16 @@ class Hangman:
|
|||
|
||||
if game.win():
|
||||
fmt += " You guys got it! The word was `{}`".format(game.word)
|
||||
del self.games[ctx.message.server.id]
|
||||
del self.games[ctx.message.guild.id]
|
||||
elif game.failed():
|
||||
fmt += " Sorry, you guys failed...the word was `{}`".format(game.word)
|
||||
del self.games[ctx.message.server.id]
|
||||
del self.games[ctx.message.guild.id]
|
||||
else:
|
||||
fmt += str(game)
|
||||
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@hangman.command(name='create', aliases=['start'], no_pm=True, pass_context=True)
|
||||
@hangman.command(name='create', aliases=['start'], no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
async def create_hangman(self, ctx):
|
||||
"""This is used to create a new hangman game
|
||||
|
@ -163,16 +163,16 @@ class Hangman:
|
|||
|
||||
# Only have one hangman game per server, since anyone
|
||||
# In a server (except the creator) can guess towards the current game
|
||||
if self.games.get(ctx.message.server.id) is not None:
|
||||
await self.bot.say("Sorry but only one Hangman game can be running per server!")
|
||||
if self.games.get(ctx.message.guild.id) is not None:
|
||||
await ctx.send("Sorry but only one Hangman game can be running per server!")
|
||||
return
|
||||
|
||||
game = self.create(random.SystemRandom().choice(phrases), ctx)
|
||||
# Let them know the game has started, then print the current game so that the blanks are shown
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Alright, a hangman game has just started, you can start guessing now!\n{}".format(str(game)))
|
||||
|
||||
@hangman.command(name='delete', aliases=['stop', 'remove', 'end'], pass_context=True, no_pm=True)
|
||||
@hangman.command(name='delete', aliases=['stop', 'remove', 'end'], no_pm=True)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
async def stop_game(self, ctx):
|
||||
"""Force stops a game of hangman
|
||||
|
@ -181,12 +181,12 @@ class Hangman:
|
|||
|
||||
EXAMPLE: !hangman stop
|
||||
RESULT: No more men being hung"""
|
||||
if self.games.get(ctx.message.server.id) is None:
|
||||
await self.bot.say("There are no Hangman games running on this server!")
|
||||
if self.games.get(ctx.message.guild.id) is None:
|
||||
await ctx.send("There are no Hangman games running on this server!")
|
||||
return
|
||||
|
||||
del self.games[ctx.message.server.id]
|
||||
await self.bot.say("I have just stopped the game of Hangman, a new should be able to be started now!")
|
||||
del self.games[ctx.message.guild.id]
|
||||
await ctx.send("I have just stopped the game of Hangman, a new should be able to be started now!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -85,7 +85,7 @@ class Interaction:
|
|||
self.battles = {}
|
||||
|
||||
def user_battling(self, ctx, player2=None):
|
||||
battling = self.battles.get(ctx.message.server.id)
|
||||
battling = self.battles.get(ctx.message.guild.id)
|
||||
|
||||
# If no one is battling, obviously the user is not battling
|
||||
if battling is None:
|
||||
|
@ -101,14 +101,14 @@ class Interaction:
|
|||
|
||||
# Handles removing the author from the dictionary of battles
|
||||
def battling_off(self, ctx):
|
||||
battles = self.battles.get(ctx.message.server.id) or {}
|
||||
battles = self.battles.get(ctx.message.guild.id) or {}
|
||||
player_id = ctx.message.author.id
|
||||
# Create a new dictionary, exactly the way the last one was setup
|
||||
# But don't include any that have the author's ID
|
||||
self.battles[ctx.message.server.id] = {p1: p2 for p1, p2 in battles.items() if
|
||||
not p2 == player_id and not p1 == player_id}
|
||||
self.battles[ctx.message.guild.id] = {p1: p2 for p1, p2 in battles.items() if
|
||||
not p2 == player_id and not p1 == player_id}
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def hug(self, ctx, user: discord.Member = None):
|
||||
"""Makes me hug a person!
|
||||
|
@ -119,9 +119,9 @@ class Interaction:
|
|||
user = ctx.message.author
|
||||
|
||||
fmt = random.SystemRandom().choice(hugs)
|
||||
await self.bot.say(fmt.format(user.display_name))
|
||||
await ctx.send(fmt.format(user.display_name))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def avatar(self, ctx, member: discord.Member = None):
|
||||
"""Provides an image for the provided person's avatar (yours if no other member is provided)
|
||||
|
@ -133,21 +133,21 @@ class Interaction:
|
|||
member = ctx.message.author
|
||||
|
||||
url = member.avatar_url
|
||||
if ctx.message.server.me.permissions_in(ctx.message.channel).attach_files:
|
||||
if ctx.message.guild.me.permissions_in(ctx.message.channel).attach_files:
|
||||
file = await utils.download_image(url)
|
||||
if file is None:
|
||||
await self.bot.say(url)
|
||||
await ctx.send(url)
|
||||
else:
|
||||
if '.gif' in url:
|
||||
filename = 'avatar.gif'
|
||||
else:
|
||||
filename = 'avatar.webp'
|
||||
file = utils.convert_to_jpeg(file)
|
||||
await self.bot.upload(file, filename=filename)
|
||||
await ctx.send(file=file, filename=filename)
|
||||
else:
|
||||
await self.bot.say(url)
|
||||
await ctx.send(url)
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@commands.group(no_pm=True, invoke_without_command=True)
|
||||
@commands.cooldown(1, 180, BucketType.user)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def battle(self, ctx, player2: discord.Member):
|
||||
|
@ -157,29 +157,29 @@ class Interaction:
|
|||
RESULT: A battle to the death"""
|
||||
if ctx.message.author.id == player2.id:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("Why would you want to battle yourself? Suicide is not the answer")
|
||||
await ctx.send("Why would you want to battle yourself? Suicide is not the answer")
|
||||
return
|
||||
if self.bot.user.id == player2.id:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("I always win, don't even try it.")
|
||||
await ctx.send("I always win, don't even try it.")
|
||||
return
|
||||
if self.user_battling(ctx, player2):
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("You or the person you are trying to battle is already in a battle!")
|
||||
await ctx.send("You or the person you are trying to battle is already in a battle!")
|
||||
return
|
||||
|
||||
# Add the author and player provided in a new battle
|
||||
battles = self.battles.get(ctx.message.server.id) or {}
|
||||
battles = self.battles.get(ctx.message.guild.id) or {}
|
||||
battles[ctx.message.author.id] = player2.id
|
||||
self.battles[ctx.message.server.id] = battles
|
||||
self.battles[ctx.message.guild.id] = battles
|
||||
|
||||
fmt = "{0.message.author.mention} has challenged you to a battle {1.mention}\n" \
|
||||
"{0.prefix}accept or {0.prefix}decline"
|
||||
# Add a call to turn off battling, if the battle is not accepted/declined in 3 minutes
|
||||
self.bot.loop.call_later(180, self.battling_off, ctx)
|
||||
await self.bot.say(fmt.format(ctx, player2))
|
||||
await ctx.send(fmt.format(ctx, player2))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def accept(self, ctx):
|
||||
"""Accepts the battle challenge
|
||||
|
@ -188,13 +188,13 @@ class Interaction:
|
|||
RESULT: Hopefully the other person's death"""
|
||||
# This is a check to make sure that the author is the one being BATTLED
|
||||
# And not the one that started the battle
|
||||
battles = self.battles.get(ctx.message.server.id) or {}
|
||||
battles = self.battles.get(ctx.message.guild.id) or {}
|
||||
p1 = [p1_id for p1_id, p2_id in battles.items() if p2_id == ctx.message.author.id]
|
||||
if len(p1) == 0:
|
||||
await self.bot.say("You are not currently being challenged to a battle!")
|
||||
await ctx.send("You are not currently being challenged to a battle!")
|
||||
return
|
||||
|
||||
battleP1 = discord.utils.find(lambda m: m.id == p1[0], ctx.message.server.members)
|
||||
battleP1 = discord.utils.find(lambda m: m.id == p1[0], ctx.message.guild.members)
|
||||
battleP2 = ctx.message.author
|
||||
|
||||
# Get a random win message from our list
|
||||
|
@ -205,13 +205,13 @@ class Interaction:
|
|||
# Randomize the order of who is printed/sent to the update system
|
||||
# All we need to do is change what order the challengers are printed/added as a paramater
|
||||
if random.SystemRandom().randint(0, 1):
|
||||
await self.bot.say(fmt.format(battleP1.mention, battleP2.mention))
|
||||
await ctx.send(fmt.format(battleP1.mention, battleP2.mention))
|
||||
await utils.update_records('battle_records', battleP1, battleP2)
|
||||
else:
|
||||
await self.bot.say(fmt.format(battleP2.mention, battleP1.mention))
|
||||
await ctx.send(fmt.format(battleP2.mention, battleP1.mention))
|
||||
await utils.update_records('battle_records', battleP2, battleP1)
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def decline(self, ctx):
|
||||
"""Declines the battle challenge
|
||||
|
@ -220,23 +220,23 @@ class Interaction:
|
|||
RESULT: You chicken out"""
|
||||
# This is a check to make sure that the author is the one being BATTLED
|
||||
# And not the one that started the battle
|
||||
battles = self.battles.get(ctx.message.server.id) or {}
|
||||
battles = self.battles.get(ctx.message.guild.id) or {}
|
||||
p1 = [p1_id for p1_id, p2_id in battles.items() if p2_id == ctx.message.author.id]
|
||||
if len(p1) == 0:
|
||||
await self.bot.say("You are not currently being challenged to a battle!")
|
||||
await ctx.send("You are not currently being challenged to a battle!")
|
||||
return
|
||||
|
||||
battleP1 = discord.utils.find(lambda m: m.id == p1[0], ctx.message.server.members)
|
||||
battleP1 = discord.utils.find(lambda m: m.id == p1[0], ctx.message.guild.members)
|
||||
battleP2 = ctx.message.author
|
||||
|
||||
# There's no need to update the stats for the members if they declined the battle
|
||||
self.battling_off(ctx)
|
||||
await self.bot.say("{0} has chickened out! What a loser~".format(battleP2.mention, battleP1.mention))
|
||||
await ctx.send("{0} has chickened out! What a loser~".format(battleP2.mention, battleP1.mention))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@commands.cooldown(1, 180, BucketType.user)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def boop(self, ctx, boopee: discord.Member = None, *, message = ""):
|
||||
async def boop(self, ctx, boopee: discord.Member = None, *, message=""):
|
||||
"""Boops the mentioned person
|
||||
|
||||
EXAMPLE: !boop @OtherPerson
|
||||
|
@ -244,18 +244,18 @@ class Interaction:
|
|||
booper = ctx.message.author
|
||||
if boopee is None:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("You try to boop the air, the air boops back. Be afraid....")
|
||||
await ctx.send("You try to boop the air, the air boops back. Be afraid....")
|
||||
return
|
||||
# To keep formatting easier, keep it either "" or the message with a space in front
|
||||
if message is not None:
|
||||
message = " " + message
|
||||
if boopee.id == booper.id:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("You can't boop yourself! Silly...")
|
||||
await ctx.send("You can't boop yourself! Silly...")
|
||||
return
|
||||
if boopee.id == self.bot.user.id:
|
||||
ctx.command.reset_cooldown(ctx)
|
||||
await self.bot.say("Why the heck are you booping me? Get away from me >:c")
|
||||
await ctx.send("Why the heck are you booping me? Get away from me >:c")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': booper.id}
|
||||
|
@ -275,7 +275,7 @@ class Interaction:
|
|||
amount = 1
|
||||
|
||||
fmt = "{0.mention} has just booped {1.mention}{3}! That's {2} times now!"
|
||||
await self.bot.say(fmt.format(booper, boopee, amount, message))
|
||||
await ctx.send(fmt.format(booper, boopee, amount, message))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -17,13 +17,15 @@ class Links:
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(pass_context=True, aliases=['g'])
|
||||
@commands.command(aliases=['g'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def google(self, ctx, *, query: str):
|
||||
"""Searches google for a provided query
|
||||
|
||||
EXAMPLE: !g Random cat pictures!
|
||||
RESULT: Links to sites with random cat pictures!"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
url = "https://www.google.com/search"
|
||||
|
||||
# Turn safe filter on or off, based on whether or not this is a nsfw channel
|
||||
|
@ -43,7 +45,7 @@ class Links:
|
|||
data = await utils.request(url, payload=params, attr='text')
|
||||
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel, "I failed to connect to google! (That can happen??)")
|
||||
await ctx.send("I failed to connect to google! (That can happen??)")
|
||||
return
|
||||
|
||||
# Convert to a BeautifulSoup element and loop through each result clasified by h3 tags with a class of 'r'
|
||||
|
@ -55,7 +57,7 @@ class Links:
|
|||
try:
|
||||
result_url = re.search('(?<=q=).*(?=&sa=)', element.find('a').get('href')).group(0)
|
||||
except AttributeError:
|
||||
await self.bot.say("I couldn't find any results for {}!".format(query))
|
||||
await ctx.send("I couldn't find any results for {}!".format(query))
|
||||
return
|
||||
|
||||
# Get the next sibling, find the span where the description is, and get the text from this
|
||||
|
@ -68,15 +70,17 @@ class Links:
|
|||
fmt += '\n\n**URL**: <{}>\n**Description**: {}'.format(result_url, description)
|
||||
|
||||
fmt = "**Top 3 results for the query** _{}_:{}".format(query, fmt)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@commands.command(aliases=['yt'], pass_context=True)
|
||||
@commands.command(aliases=['yt'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def youtube(self, ctx, *, query: str):
|
||||
"""Searches youtube for a provided query
|
||||
|
||||
EXAMPLE: !youtube Cat videos!
|
||||
RESULT: Cat videos!"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
key = utils.youtube_key
|
||||
url = "https://www.googleapis.com/youtube/v3/search"
|
||||
params = {'key': key,
|
||||
|
@ -87,13 +91,13 @@ class Links:
|
|||
data = await utils.request(url, payload=params)
|
||||
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel, "Sorry but I failed to connect to youtube!")
|
||||
await ctx.send("Sorry but I failed to connect to youtube!")
|
||||
return
|
||||
|
||||
try:
|
||||
result = data['items'][0]
|
||||
except IndexError:
|
||||
await self.bot.say("I could not find any results with the search term {}".format(query))
|
||||
await ctx.send("I could not find any results with the search term {}".format(query))
|
||||
return
|
||||
|
||||
result_url = "https://youtube.com/watch?v={}".format(result['id']['videoId'])
|
||||
|
@ -101,15 +105,17 @@ class Links:
|
|||
description = result['snippet']['description']
|
||||
|
||||
fmt = "**Title:** {}\n\n**Description:** {}\n\n**URL:** <{}>".format(title, description, result_url)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def wiki(self, ctx, *, query: str):
|
||||
"""Pulls the top match for a specific term from wikipedia, and returns the result
|
||||
|
||||
EXAMPLE: !wiki Test
|
||||
RESULT: A link to the wikipedia article for the word test"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
# All we need to do is search for the term provided, so the action, list, and format never need to change
|
||||
base_url = "https://en.wikipedia.org/w/api.php"
|
||||
params = {"action": "query",
|
||||
|
@ -120,11 +126,11 @@ class Links:
|
|||
data = await utils.request(base_url, payload=params)
|
||||
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel, "Sorry but I failed to connect to Wikipedia!")
|
||||
await ctx.send("Sorry but I failed to connect to Wikipedia!")
|
||||
return
|
||||
|
||||
if len(data['query']['search']) == 0:
|
||||
await self.bot.say("I could not find any results with that term, I tried my best :c")
|
||||
await ctx.send("I could not find any results with that term, I tried my best :c")
|
||||
return
|
||||
# Wiki articles' URLs are in the format https://en.wikipedia.org/wiki/[Titlehere]
|
||||
# Replace spaces with %20
|
||||
|
@ -136,44 +142,48 @@ class Links:
|
|||
snippet = re.sub('</span>', '', snippet)
|
||||
snippet = re.sub('"', '"', snippet)
|
||||
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Here is the best match I found with the query `{}`:\nURL: <{}>\nSnippet: \n```\n{}```".format(query, url,
|
||||
snippet))
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def urban(self, ctx, *, msg: str):
|
||||
"""Pulls the top urbandictionary.com definition for a term
|
||||
|
||||
EXAMPLE: !urban a normal phrase
|
||||
RESULT: Probably something lewd; this is urban dictionary we're talking about"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
url = "http://api.urbandictionary.com/v0/define"
|
||||
params = {"term": msg}
|
||||
try:
|
||||
data = await utils.request(url, payload=params)
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel, "Sorry but I failed to connect to urban dictionary!")
|
||||
await ctx.send("Sorry but I failed to connect to urban dictionary!")
|
||||
return
|
||||
|
||||
# List is the list of definitions found, if it's empty then nothing was found
|
||||
if len(data['list']) == 0:
|
||||
await self.bot.say("No result with that term!")
|
||||
await ctx.send("No result with that term!")
|
||||
# If the list is not empty, use the first result and print it's defintion
|
||||
else:
|
||||
await self.bot.say(data['list'][0]['definition'])
|
||||
await ctx.send(data['list'][0]['definition'])
|
||||
# Urban dictionary has some long definitions, some might not be able to be sent
|
||||
except discord.HTTPException:
|
||||
await self.bot.say('```\nError: Definition is too long for me to send```')
|
||||
await ctx.send('```\nError: Definition is too long for me to send```')
|
||||
except KeyError:
|
||||
await self.bot.say("Sorry but I failed to connect to urban dictionary!")
|
||||
await ctx.send("Sorry but I failed to connect to urban dictionary!")
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def derpi(self, ctx, *search: str):
|
||||
"""Provides a random image from the first page of derpibooru.org for the following term
|
||||
|
||||
EXAMPLE: !derpi Rainbow Dash
|
||||
RESULT: A picture of Rainbow Dash!"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
if len(search) > 0:
|
||||
url = 'https://derpibooru.org/search.json'
|
||||
|
||||
|
@ -192,18 +202,16 @@ class Links:
|
|||
else:
|
||||
params['q'] += ", safe"
|
||||
|
||||
await self.bot.say("Looking up an image with those tags....")
|
||||
|
||||
try:
|
||||
# Get the response from derpibooru and parse the 'search' result from it
|
||||
data = await utils.request(url, payload=params)
|
||||
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel, "Sorry but I failed to connect to Derpibooru!")
|
||||
await ctx.send("Sorry but I failed to connect to Derpibooru!")
|
||||
return
|
||||
results = data['search']
|
||||
except KeyError:
|
||||
await self.bot.say("No results with that search term, {0}!".format(ctx.message.author.mention))
|
||||
await ctx.send("No results with that search term, {0}!".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
# The first request we've made ensures there are results
|
||||
|
@ -215,7 +223,7 @@ class Links:
|
|||
params['page'] = random.SystemRandom().randint(1, pages)
|
||||
data = await utils.request(url, payload=params)
|
||||
if data is None:
|
||||
await self.bot.say("Sorry but I failed to connect to Derpibooru!")
|
||||
await ctx.send("Sorry but I failed to connect to Derpibooru!")
|
||||
return
|
||||
# Now get the results again
|
||||
results = data['search']
|
||||
|
@ -224,16 +232,16 @@ class Links:
|
|||
index = random.SystemRandom().randint(0, len(results) - 1)
|
||||
image_link = 'https://derpibooru.org/{}'.format(results[index]['id'])
|
||||
else:
|
||||
await self.bot.say("No results with that search term, {0}!".format(ctx.message.author.mention))
|
||||
await ctx.send("No results with that search term, {0}!".format(ctx.message.author.mention))
|
||||
return
|
||||
else:
|
||||
# If no search term was provided, search for a random image
|
||||
# .url will be the URL we end up at, not the one requested.
|
||||
# https://derpibooru.org/images/random redirects to a random image, so this is exactly what we want
|
||||
image_link = await utils.request('https://derpibooru.org/images/random', attr='url')
|
||||
await self.bot.say(image_link)
|
||||
await ctx.send(image_link)
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def e621(self, ctx, *, tags: str):
|
||||
"""Searches for a random image from e621.net
|
||||
|
@ -242,19 +250,17 @@ class Links:
|
|||
|
||||
EXAMPLE: !e621 dragon
|
||||
RESULT: A picture of a dragon (hopefully, screw your tagging system e621)"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
# This changes the formatting for queries, so we don't
|
||||
# Have to use e621's stupid formatting when using the command
|
||||
|
||||
tags = tags.replace(' ', '_')
|
||||
tags = tags.replace(',_', ' ')
|
||||
|
||||
url = 'https://e621.net/post/index.json'
|
||||
params = {'limit': 320,
|
||||
'tags': tags}
|
||||
# e621 provides a way to change how many images can be shown on one request
|
||||
# This gives more of a chance of random results, however it causes the lookup to take longer than most
|
||||
# Due to this, send a message saying we're looking up the information first
|
||||
await self.bot.say("Looking up an image with those tags....")
|
||||
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
nsfw_channels = await utils.get_content("nsfw_channels", r_filter)
|
||||
|
@ -266,8 +272,7 @@ class Links:
|
|||
data = await utils.request(url, payload=params)
|
||||
|
||||
if data is None:
|
||||
await self.bot.send_message(ctx.message.channel,
|
||||
"Sorry, I had trouble connecting at the moment; please try again later")
|
||||
await ctx.send("Sorry, I had trouble connecting at the moment; please try again later")
|
||||
return
|
||||
|
||||
# Try to find an image from the list. If there were no results, we're going to attempt to find
|
||||
|
@ -276,9 +281,9 @@ class Links:
|
|||
# i.e. it responded with a 404/504/etc.
|
||||
try:
|
||||
rand_image = data[random.SystemRandom().randint(0, len(data) - 1)]['file_url']
|
||||
await self.bot.say(rand_image)
|
||||
await ctx.send(rand_image)
|
||||
except (ValueError, KeyError):
|
||||
await self.bot.say("No results with that tag {}".format(ctx.message.author.mention))
|
||||
await ctx.send("No results with that tag {}".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
|
||||
|
|
227
cogs/mod.py
227
cogs/mod.py
|
@ -16,53 +16,30 @@ class Mod:
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
def find_command(self, command):
|
||||
# This method ensures the command given is valid. We need to loop through commands
|
||||
# As self.bot.commands only includes parent commands
|
||||
# So we are splitting the command in parts, looping through the commands
|
||||
# And getting the subcommand based on the next part
|
||||
# If we try to access commands of a command that isn't a group
|
||||
# We'll hit an AttributeError, meaning an invalid command was given
|
||||
# If we loop through and don't find anything, cmd will still be None
|
||||
# And we'll report an invalid was given as well
|
||||
cmd = None
|
||||
|
||||
for part in command.split():
|
||||
try:
|
||||
if cmd is None:
|
||||
cmd = self.bot.commands.get(part)
|
||||
else:
|
||||
cmd = cmd.commands.get(part)
|
||||
except AttributeError:
|
||||
cmd = None
|
||||
break
|
||||
|
||||
return cmd
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True, aliases=['nick'])
|
||||
@commands.command(no_pm=True, aliases=['nick'])
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def nickname(self, ctx, *, name=None):
|
||||
"""Used to set the nickname for Bonfire (provide no nickname and it will reset)
|
||||
|
||||
EXAMPLE: !nick Music Bot
|
||||
RESULT: My nickname is now music bot"""
|
||||
await self.bot.change_nickname(ctx.message.server.me, name)
|
||||
await self.bot.say("\N{OK HAND SIGN}")
|
||||
RESULT: My nickname is now Music Bot"""
|
||||
await ctx.message.server.me.edit(nick=name)
|
||||
await ctx.send("\N{OK HAND SIGN}")
|
||||
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def kick(self, member: discord.Member):
|
||||
async def kick(self, ctx, member: discord.Member):
|
||||
"""Used to kick a member from this server
|
||||
|
||||
EXAMPLE: !kick @Member
|
||||
RESULT: They're kicked from the server?"""
|
||||
try:
|
||||
await self.bot.kick(member)
|
||||
await self.bot.say("\N{OK HAND SIGN}")
|
||||
await member.kick()
|
||||
await ctx.send("\N{OK HAND SIGN}")
|
||||
except discord.Forbidden:
|
||||
await self.bot.say("But I can't, muh permissions >:c")
|
||||
await ctx.send("But I can't, muh permissions >:c")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(ban_members=True)
|
||||
async def unban(self, ctx, member_id: int):
|
||||
"""Used to unban a member from this server
|
||||
|
@ -74,16 +51,15 @@ class Mod:
|
|||
|
||||
# Lets only accept an int for this method, in order to ensure only an ID is provided
|
||||
# Due to that though, we need to ensure a string is passed as the member's ID
|
||||
member = discord.Object(id=str(member_id))
|
||||
try:
|
||||
await self.bot.unban(ctx.message.server, member)
|
||||
await self.bot.say("\N{OK HAND SIGN}")
|
||||
await discord.http.unban(member_id, ctx.guild.id)
|
||||
await ctx.send("\N{OK HAND SIGN}")
|
||||
except discord.Forbidden:
|
||||
await self.bot.say("But I can't, muh permissions >:c")
|
||||
await ctx.send("But I can't, muh permissions >:c")
|
||||
except discord.HTTPException:
|
||||
await self.bot.say("Sorry, I failed to unban that user!")
|
||||
await ctx.send("Sorry, I failed to unban that user!")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(ban_members=True)
|
||||
async def ban(self, ctx, *, member):
|
||||
"""Used to ban a member
|
||||
|
@ -95,31 +71,35 @@ class Mod:
|
|||
|
||||
# Lets first check if a user ID was provided, as that will be the easiest case to ban
|
||||
if member.isdigit():
|
||||
# First convert it to a discord object based on the ID that was given
|
||||
member = discord.Object(id=member)
|
||||
# Next, to ban from the server the API takes a server obejct and uses that ID
|
||||
# So set "this" server as the member's server. This creates the "fake" member we need
|
||||
member.server = ctx.message.server
|
||||
try:
|
||||
await discord.http.ban(member, ctx.guild.id)
|
||||
await ctx.send("\N{OK HAND SIGN}")
|
||||
except discord.Forbidden:
|
||||
await ctx.send("But I can't, muh permissions >:c")
|
||||
except discord.HTTPException:
|
||||
await ctx.send("Sorry, I failed to ban that user!")
|
||||
finally:
|
||||
return
|
||||
else:
|
||||
# If no ID was provided, lets try to convert what was given using the internal coverter
|
||||
converter = commands.converter.UserConverter(ctx, member)
|
||||
converter = commands.converter.MemberConverter(ctx, member)
|
||||
try:
|
||||
member = converter.convert()
|
||||
except commands.converter.BadArgument:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
'{} does not appear to be a valid member. If this member is not in this server, please provide '
|
||||
'their ID'.format(member))
|
||||
return
|
||||
# Now lets try actually banning the member we've been given
|
||||
try:
|
||||
await self.bot.ban(member)
|
||||
await self.bot.say("\N{OK HAND SIGN}")
|
||||
await member.ban()
|
||||
await ctx.send("\N{OK HAND SIGN}")
|
||||
except discord.Forbidden:
|
||||
await self.bot.say("But I can't, muh permissions >:c")
|
||||
await ctx.send("But I can't, muh permissions >:c")
|
||||
except discord.HTTPException:
|
||||
await self.bot.say("Sorry, I failed to ban that user!")
|
||||
await ctx.send("Sorry, I failed to ban that user!")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def alerts(self, ctx, channel: discord.Channel):
|
||||
"""This command is used to set a channel as the server's 'notifications' channel
|
||||
|
@ -132,10 +112,10 @@ class Mod:
|
|||
'channel_id': channel.id}
|
||||
if not await utils.add_content('server_alerts', entry, r_filter):
|
||||
await utils.update_content('server_alerts', entry, r_filter)
|
||||
await self.bot.say("I have just changed this server's 'notifications' channel"
|
||||
"\nAll notifications will now go to `{}`".format(channel))
|
||||
await ctx.send("I have just changed this server's 'notifications' channel"
|
||||
"\nAll notifications will now go to `{}`".format(channel))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def usernotify(self, ctx, on_off: str):
|
||||
"""This command can be used to set whether or not you want user notificaitons to show
|
||||
|
@ -148,22 +128,21 @@ class Mod:
|
|||
# So we base this channel on it's own and not from alerts
|
||||
# When mod logging becomes available, that will be kept to it's own channel if wanted as well
|
||||
on_off = ctx.message.channel.id if re.search("(on|yes|true)", on_off.lower()) else None
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
entry = {'server_id': ctx.message.guild.id,
|
||||
'channel_id': on_off}
|
||||
if not await utils.add_content('user_notifications', entry, r_filter):
|
||||
await utils.update_content('user_notifications', entry, r_filter)
|
||||
fmt = "notify" if on_off else "not notify"
|
||||
await self.bot.say("This server will now {} if someone has joined or left".format(fmt))
|
||||
await ctx.send("This server will now {} if someone has joined or left".format(fmt))
|
||||
|
||||
@commands.group(pass_context=True)
|
||||
@commands.group()
|
||||
async def nsfw(self, ctx):
|
||||
"""Handles adding or removing a channel as a nsfw channel"""
|
||||
# This command isn't meant to do anything, so just send an error if an invalid subcommand is passed
|
||||
if ctx.invoked_subcommand is None:
|
||||
await self.bot.say('Invalid subcommand passed: {0.subcommand_passed}'.format(ctx))
|
||||
pass
|
||||
|
||||
@nsfw.command(name="add", pass_context=True)
|
||||
@nsfw.command(name="add")
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def nsfw_add(self, ctx):
|
||||
"""Registers this channel as a 'nsfw' channel
|
||||
|
@ -172,11 +151,11 @@ class Mod:
|
|||
RESULT: ;)"""
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
if await utils.add_content('nsfw_channels', r_filter, r_filter):
|
||||
await self.bot.say("This channel has just been registered as 'nsfw'! Have fun you naughties ;)")
|
||||
await ctx.send("This channel has just been registered as 'nsfw'! Have fun you naughties ;)")
|
||||
else:
|
||||
await self.bot.say("This channel is already registered as 'nsfw'!")
|
||||
await ctx.send("This channel is already registered as 'nsfw'!")
|
||||
|
||||
@nsfw.command(name="remove", aliases=["delete"], pass_context=True)
|
||||
@nsfw.command(name="remove", aliases=["delete"])
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def nsfw_remove(self, ctx):
|
||||
"""Removes this channel as a 'nsfw' channel
|
||||
|
@ -185,11 +164,11 @@ class Mod:
|
|||
RESULT: ;("""
|
||||
r_filter = {'channel_id': ctx.message.channel.id}
|
||||
if await utils.remove_content('nsfw_channels', r_filter):
|
||||
await self.bot.say("This channel has just been unregistered as a nsfw channel")
|
||||
await ctx.send("This channel has just been unregistered as a nsfw channel")
|
||||
else:
|
||||
await self.bot.say("This channel is not registered as a ''nsfw' channel!")
|
||||
await ctx.send("This channel is not registered as a ''nsfw' channel!")
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def say(self, ctx, *, msg: str):
|
||||
"""Tells the bot to repeat what you say
|
||||
|
@ -197,13 +176,13 @@ class Mod:
|
|||
EXAMPLE: !say I really like orange juice
|
||||
RESULT: I really like orange juice"""
|
||||
fmt = "\u200B{}".format(msg)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
try:
|
||||
await self.bot.delete_message(ctx.message)
|
||||
await ctx.message.delete()
|
||||
except:
|
||||
pass
|
||||
|
||||
@commands.group(pass_context=True, invoke_without_command=True, no_pm=True)
|
||||
@commands.group(invoke_without_command=True, no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def perms(self, ctx, *, command: str = None):
|
||||
"""This command can be used to print the current allowed permissions on a specific command
|
||||
|
@ -212,20 +191,20 @@ class Mod:
|
|||
EXAMPLE: !perms help RESULT: Hopefully a result saying you just need send_messages permissions; otherwise lol
|
||||
this server's admin doesn't like me """
|
||||
if command is None:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Valid permissions are: ```\n{}```".format("\n".join("{}".format(i) for i in valid_perms)))
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
server_perms = await utils.get_content('custom_permissions', r_filter)
|
||||
try:
|
||||
server_perms = server_perms[0]
|
||||
except TypeError:
|
||||
server_perms = {}
|
||||
cmd = self.find_command(command)
|
||||
cmd = self.bot.get_command(command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say("That is not a valid command!")
|
||||
await ctx.send("That is not a valid command!")
|
||||
return
|
||||
|
||||
perms_value = server_perms.get(cmd.qualified_name)
|
||||
|
@ -240,15 +219,15 @@ class Mod:
|
|||
# Able to manage the server (for the utils on perm commands)
|
||||
for func in cmd.utils:
|
||||
if "is_owner" in func.__qualname__:
|
||||
await self.bot.say("You need to own the bot to run this command")
|
||||
await ctx.send("You need to own the bot to run this command")
|
||||
return
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"You are required to have `manage_server` permissions to run `{}`".format(cmd.qualified_name))
|
||||
return
|
||||
|
||||
# Perms will be an attribute if custom_perms is found no matter what, so no need to check this
|
||||
perms = "\n".join(attribute for attribute, setting in custom_perms.perms.items() if setting)
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"You are required to have `{}` permissions to run `{}`".format(perms, cmd.qualified_name))
|
||||
else:
|
||||
# Permissions are saved as bit values, so create an object based on that value
|
||||
|
@ -256,10 +235,10 @@ class Mod:
|
|||
# There's no need to check for errors here, as we ensure a permission is valid when adding it
|
||||
permissions = discord.Permissions(perms_value)
|
||||
needed_perm = [perm[0] for perm in permissions if perm[1]][0]
|
||||
await self.bot.say("You need to have the permission `{}` "
|
||||
"to use the command `{}` in this server".format(needed_perm, command))
|
||||
await ctx.send("You need to have the permission `{}` "
|
||||
"to use the command `{}` in this server".format(needed_perm, command))
|
||||
|
||||
@perms.command(name="add", aliases=["setup,create"], pass_context=True, no_pm=True)
|
||||
@perms.command(name="add", aliases=["setup,create"], no_pm=True)
|
||||
@commands.has_permissions(manage_server=True)
|
||||
async def add_perms(self, ctx, *msg: str):
|
||||
"""Sets up custom permissions on the provided command
|
||||
|
@ -274,8 +253,8 @@ class Mod:
|
|||
try:
|
||||
permissions = msg[len(msg) - 1]
|
||||
except IndexError:
|
||||
await self.bot.say("Please provide the permissions you want to setup, the format for this must be in:\n"
|
||||
"`perms add <command> <permission>`")
|
||||
await ctx.send("Please provide the permissions you want to setup, the format for this must be in:\n"
|
||||
"`perms add <command> <permission>`")
|
||||
return
|
||||
|
||||
# If a user can run a command, they have to have send_messages permissions; so use this as the base
|
||||
|
@ -288,15 +267,15 @@ class Mod:
|
|||
try:
|
||||
setattr(perm_obj, permissions, True)
|
||||
except AttributeError:
|
||||
await self.bot.say("{} does not appear to be a valid permission! Valid permissions are: ```\n{}```"
|
||||
.format(permissions, "\n".join(valid_perms)))
|
||||
await ctx.send("{} does not appear to be a valid permission! Valid permissions are: ```\n{}```"
|
||||
.format(permissions, "\n".join(valid_perms)))
|
||||
return
|
||||
perm_value = perm_obj.value
|
||||
|
||||
cmd = self.find_command(command)
|
||||
cmd = self.bot.get_command(command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"That command does not exist! You can't have custom permissions on a non-existant command....")
|
||||
return
|
||||
|
||||
|
@ -305,12 +284,12 @@ class Mod:
|
|||
# Which means I do not want to check custom permissions at all
|
||||
# Currently the second case is only on adding and removing permissions, to avoid abuse on these
|
||||
for check in cmd.checks:
|
||||
if "is_owner" == check.__name__ or re.search("has_permissions", str(check)) is not None:
|
||||
await self.bot.say("This command cannot have custom permissions setup!")
|
||||
if "is_owner" == check.__name__ or "has_permissions" not in str(check):
|
||||
await ctx.send("This command cannot have custom permissions setup!")
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
entry = {'server_id': ctx.message.guild.id,
|
||||
cmd.qualified_name: perm_value}
|
||||
|
||||
# In all other cases, I've used add_content before update_content
|
||||
|
@ -322,10 +301,10 @@ class Mod:
|
|||
|
||||
# Same case as prefixes, for now, trigger a manual update
|
||||
self.bot.loop.create_task(utils.cache['custom_permissions'].update())
|
||||
await self.bot.say("I have just added your custom permissions; "
|
||||
"you now need to have `{}` permissions to use the command `{}`".format(permissions, command))
|
||||
await ctx.send("I have just added your custom permissions; "
|
||||
"you now need to have `{}` permissions to use the command `{}`".format(permissions, command))
|
||||
|
||||
@perms.command(name="remove", aliases=["delete"], pass_context=True, no_pm=True)
|
||||
@perms.command(name="remove", aliases=["delete"], no_pm=True)
|
||||
@commands.has_permissions(manage_server=True)
|
||||
async def remove_perms(self, ctx, *, command: str):
|
||||
"""Removes the custom permissions setup on the command specified
|
||||
|
@ -333,32 +312,32 @@ class Mod:
|
|||
EXAMPLE: !perms remove play
|
||||
RESULT: Freedom!"""
|
||||
|
||||
cmd = self.find_command(command)
|
||||
cmd = self.bot.get_command(command)
|
||||
|
||||
if cmd is None:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"That command does not exist! You can't have custom permissions on a non-existant command....")
|
||||
return
|
||||
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
await utils.replace_content('custom_permissions', r.row.without(cmd.qualified_name), r_filter)
|
||||
await self.bot.say("I have just removed the custom permissions for {}!".format(cmd))
|
||||
await ctx.send("I have just removed the custom permissions for {}!".format(cmd))
|
||||
|
||||
# Same case as prefixes, for now, trigger a manual update
|
||||
self.bot.loop.create_task(utils.cache['custom_permissions'].update())
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@utils.custom_perms(manage_server=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(manage_guild=True)
|
||||
async def prefix(self, ctx, *, prefix: str):
|
||||
"""This command can be used to set a custom prefix per server
|
||||
|
||||
EXAMPLE: !prefix new_prefix
|
||||
RESULT: You probably screwing it up and not realizing you now need to do new_prefixprefix"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
if prefix.lower().strip() == "none":
|
||||
prefix = None
|
||||
|
||||
entry = {'server_id': ctx.message.server.id,
|
||||
entry = {'server_id': ctx.message.guild.id,
|
||||
'prefix': prefix}
|
||||
|
||||
if not await utils.add_content('prefixes', entry, r_filter):
|
||||
|
@ -369,9 +348,9 @@ class Mod:
|
|||
else:
|
||||
fmt = "I have just updated the prefix for this server; you now need to call commands with `{0}`. " \
|
||||
"For example, you can call this command again with {0}prefix".format(prefix)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(manage_messages=True)
|
||||
async def purge(self, ctx, limit: int = 100):
|
||||
"""This command is used to a purge a number of messages from the channel
|
||||
|
@ -379,18 +358,18 @@ class Mod:
|
|||
EXAMPLE: !purge 50
|
||||
RESULT: -50 messages in this channel"""
|
||||
if not ctx.message.channel.permissions_for(ctx.message.server.me).manage_messages:
|
||||
await self.bot.say("I do not have permission to delete messages...")
|
||||
await ctx.send("I do not have permission to delete messages...")
|
||||
return
|
||||
try:
|
||||
await self.bot.purge_from(ctx.message.channel, limit=limit)
|
||||
await ctx.message.channel.purge(limit=limit)
|
||||
except discord.HTTPException:
|
||||
await self.bot.send_message(ctx.message.channel, "Detected messages that are too far "
|
||||
"back for me to delete; I can only bulk delete messages"
|
||||
" that are under 14 days old.")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(manage_messages=True)
|
||||
async def prune(self, ctx, limit = None):
|
||||
async def prune(self, ctx, limit=None):
|
||||
"""This command can be used to prune messages from certain members
|
||||
Mention any user you want to prune messages from; if no members are mentioned, the messages removed will be mine
|
||||
If no limit is provided, then 100 will be used. This is also the max limit we can use
|
||||
|
@ -414,8 +393,9 @@ class Mod:
|
|||
# If no members are provided, assume we're trying to prune our own messages
|
||||
members = ctx.message.mentions
|
||||
roles = ctx.message.role_mentions
|
||||
|
||||
if len(members) == 0:
|
||||
members = [ctx.message.server.me]
|
||||
members = [ctx.message.guild.me]
|
||||
|
||||
# Our check for if a message should be deleted
|
||||
def check(m):
|
||||
|
@ -437,36 +417,37 @@ class Mod:
|
|||
async for msg in self.bot.logs_from(ctx.message.channel, before=ctx.message):
|
||||
if check(msg):
|
||||
try:
|
||||
await self.bot.delete_message(msg)
|
||||
await msg.delete()
|
||||
count += 1
|
||||
except:
|
||||
pass
|
||||
if count >= limit:
|
||||
break
|
||||
msg = await self.bot.say("{} messages succesfully deleted".format(count))
|
||||
|
||||
msg = await ctx.send("{} messages succesfully deleted".format(count))
|
||||
await asyncio.sleep(5)
|
||||
try:
|
||||
await self.bot.delete_message(msg)
|
||||
await self.bot.delete_message(ctx.message)
|
||||
except discord.NotFound:
|
||||
await msg.delete()
|
||||
await ctx.message.delete()
|
||||
except:
|
||||
pass
|
||||
|
||||
@commands.group(aliases=['rule'], pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@commands.group(aliases=['rule'], no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def rules(self, ctx, rule: int = None):
|
||||
"""This command can be used to view the current rules on the server
|
||||
|
||||
EXAMPLE: !rules 5
|
||||
RESULT: Rule 5 is printed"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
rules = await utils.get_content('rules', r_filter)
|
||||
try:
|
||||
rules = rules[0]['rules']
|
||||
except TypeError:
|
||||
await self.bot.say("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
await ctx.send("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
return
|
||||
if len(rules) == 0:
|
||||
await self.bot.say("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
await ctx.send("This server currently has no rules on it! I see you like to live dangerously...")
|
||||
return
|
||||
|
||||
if rule is None:
|
||||
|
@ -475,16 +456,16 @@ class Mod:
|
|||
pages.title = "Rules for {}".format(ctx.message.server.name)
|
||||
await pages.paginate()
|
||||
except utils.CannotPaginate as e:
|
||||
await self.bot.say(str(e))
|
||||
await ctx.send(str(e))
|
||||
else:
|
||||
try:
|
||||
fmt = rules[rule - 1]
|
||||
except IndexError:
|
||||
await self.bot.say("That rules does not exist.")
|
||||
await ctx.send("That rules does not exist.")
|
||||
return
|
||||
await self.bot.say("Rule {}: \"{}\"".format(rule, fmt))
|
||||
await ctx.send("Rule {}: \"{}\"".format(rule, fmt))
|
||||
|
||||
@rules.command(name='add', aliases=['create'], pass_context=True, no_pm=True)
|
||||
@rules.command(name='add', aliases=['create'], no_pm=True)
|
||||
@utils.custom_perms(manage_server=True)
|
||||
async def rules_add(self, ctx, *, rule: str):
|
||||
"""Adds a rule to this server's rules
|
||||
|
@ -498,9 +479,9 @@ class Mod:
|
|||
if not await utils.update_content('rules', update, r_filter):
|
||||
await utils.add_content('rules', entry, r_filter)
|
||||
|
||||
await self.bot.say("I have just saved your new rule, use the rules command to view this server's current rules")
|
||||
await ctx.send("I have just saved your new rule, use the rules command to view this server's current rules")
|
||||
|
||||
@rules.command(name='remove', aliases=['delete'], pass_context=True, no_pm=True)
|
||||
@rules.command(name='remove', aliases=['delete'], no_pm=True)
|
||||
@utils.custom_perms(manage_server=True)
|
||||
async def rules_delete(self, ctx, rule: int):
|
||||
"""Removes one of the rules from the list of this server's rules
|
||||
|
@ -511,9 +492,9 @@ class Mod:
|
|||
r_filter = {'server_id': ctx.message.server.id}
|
||||
update = {'rules': r.row['rules'].delete_at(rule - 1)}
|
||||
if not await utils.update_content('rules', update, r_filter):
|
||||
await self.bot.say("That is not a valid rule number, try running the command again.")
|
||||
await ctx.send("That is not a valid rule number, try running the command again.")
|
||||
else:
|
||||
await self.bot.say("I have just removed that rule from your list of rules!")
|
||||
await ctx.send("I have just removed that rule from your list of rules!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
99
cogs/osu.py
99
cogs/osu.py
|
@ -1,46 +1,18 @@
|
|||
from .utils import config
|
||||
from .utils import checks
|
||||
from .utils import images
|
||||
from . import utils
|
||||
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import aiohttp
|
||||
|
||||
# https://github.com/ppy/osu-api/wiki
|
||||
base_url = 'https://osu.ppy.sh/api/'
|
||||
BASE_URL = 'https://osu.ppy.sh/api/'
|
||||
MAX_RETRIES = 5
|
||||
|
||||
|
||||
class Osu:
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.headers = {'User-Agent': config.user_agent}
|
||||
self.key = config.osu_key
|
||||
|
||||
async def _request(self, payload, endpoint):
|
||||
"""Handles requesting to the API"""
|
||||
|
||||
# Format the URL we'll need based on the base_url, and the endpoint we want to hit
|
||||
url = "{}{}".format(base_url, endpoint)
|
||||
|
||||
# Check if our key was added, if it wasn't, add it
|
||||
key = payload.get('k', self.key)
|
||||
payload['k'] = key
|
||||
|
||||
# Attempt to connect up to our max retries
|
||||
for x in range(MAX_RETRIES):
|
||||
try:
|
||||
async with aiohttp.get(url, headers=self.headers, params=payload) as r:
|
||||
# If we failed to connect, attempt again
|
||||
if r.status != 200:
|
||||
continue
|
||||
|
||||
data = await r.json()
|
||||
return data
|
||||
# If any error happened when making the request, attempt again
|
||||
except:
|
||||
continue
|
||||
self.key = utils.osu_key
|
||||
self.payload = {'k': self.key}
|
||||
|
||||
async def find_beatmap(self, query):
|
||||
"""Finds a beatmap ID based on the first match of searching a beatmap"""
|
||||
|
@ -48,21 +20,22 @@ class Osu:
|
|||
|
||||
async def get_beatmap(self, b_id):
|
||||
"""Gets beatmap info based on the ID provided"""
|
||||
params = {'b': b_id}
|
||||
endpoint = 'get_beatmaps'
|
||||
data = await self._request(params, endpoint)
|
||||
payload = self.payload.copy()
|
||||
payload['b'] = b_id
|
||||
url = BASE_URL + 'get_beatmaps'
|
||||
data = await utils.request(url, payload=payload)
|
||||
try:
|
||||
return data[0]
|
||||
except IndexError:
|
||||
except (IndexError, TypeError):
|
||||
return None
|
||||
|
||||
@commands.group(pass_context=True, invoke_without_command=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.group(invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def osu(self, ctx):
|
||||
pass
|
||||
|
||||
@osu.command(name='scores', aliases=['score'], pass_context=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@osu.command(name='scores', aliases=['score'])
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def osu_user_scores(self, ctx, user, song=1):
|
||||
"""Used to get the top scores for a user
|
||||
You can provide either your Osu ID or your username
|
||||
|
@ -73,7 +46,7 @@ class Osu:
|
|||
EXAMPLE: !osu MyUsername 5
|
||||
RESULT: Info about your 5th best song"""
|
||||
|
||||
await self.bot.say("Looking up your Osu information...")
|
||||
await ctx.send("Looking up your Osu information...")
|
||||
# To make this easy for the user, it's indexed starting at 1, so lets subtract by 1
|
||||
song -= 1
|
||||
# Make sure the song is not negative however, if so set to 0
|
||||
|
@ -93,17 +66,18 @@ class Osu:
|
|||
'countmiss': 'misses',
|
||||
'perfect': 'got_max_combo'}
|
||||
|
||||
params = {'u': user,
|
||||
'limit': 100}
|
||||
# The endpoint that we're accessing to get this informatin
|
||||
endpoint = 'get_user_best'
|
||||
data = await self._request(params, endpoint)
|
||||
payload = self.payload.copy()
|
||||
payload['u'] = user
|
||||
payload['limit'] = 100
|
||||
# The endpoint that we're accessing to get this information
|
||||
url = BASE_URL + 'get_user_beat'
|
||||
data = await utils.request(url, payload=payload)
|
||||
|
||||
try:
|
||||
data = data[song]
|
||||
except IndexError:
|
||||
if len(data) == 0:
|
||||
await self.bot.say("I could not find any top songs for the user {}".format(user))
|
||||
except (IndexError, TypeError):
|
||||
if data is not None and len(data) == 0:
|
||||
await ctx.send("I could not find any top songs for the user {}".format(user))
|
||||
return
|
||||
else:
|
||||
data = data[len(data) - 1]
|
||||
|
@ -130,14 +104,14 @@ class Osu:
|
|||
# Attempt to create our banner and upload that
|
||||
# If we can't find the images needed, or don't have permissions, just send a message instead
|
||||
try:
|
||||
banner = await images.create_banner(ctx.message.author, "Osu User Stats", fmt)
|
||||
banner = await utils.create_banner(ctx.message.author, "Osu User Stats", fmt)
|
||||
await self.bot.upload(banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
_fmt = "\n".join("{}: {}".format(k, r) for k, r in fmt)
|
||||
await self.bot.say("```\n{}```".format(_fmt))
|
||||
await ctx.send("```\n{}```".format(_fmt))
|
||||
|
||||
@osu.command(name='user', pass_context=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def osu_user_info(self, ctx, *, user):
|
||||
"""Used to get information about a specific user
|
||||
You can provide either your Osu ID or your username
|
||||
|
@ -147,7 +121,7 @@ class Osu:
|
|||
EXAMPLE: !osu user MyUserName
|
||||
RESULT: Info about your user"""
|
||||
|
||||
await self.bot.say("Looking up your Osu information...")
|
||||
await ctx.send("Looking up your Osu information...")
|
||||
# A list of the possible values we'll receive, that we want to display
|
||||
wanted_info = ['username', 'playcount', 'ranked_score', 'pp_rank', 'level', 'pp_country_rank',
|
||||
'accuracy', 'country', 'pp_country_rank', 'count_rank_s', 'count_rank_a']
|
||||
|
@ -159,16 +133,17 @@ class Osu:
|
|||
'count_rank_a': 'total_a_ranks'}
|
||||
|
||||
# The paramaters that we'll send to osu to get the information needed
|
||||
params = {'u': user}
|
||||
# The endpoint that we're accessing to get this informatin
|
||||
endpoint = 'get_user'
|
||||
data = await self._request(params, endpoint)
|
||||
payload = self.payload.copy()
|
||||
payload['u'] = user
|
||||
# The endpoint that we're accessing to get this information
|
||||
url = BASE_URL + 'get_user'
|
||||
data = await utils.request(url, payload=payload)
|
||||
|
||||
# Make sure we found a result, we should only find one with the way we're searching
|
||||
try:
|
||||
data = data[0]
|
||||
except IndexError:
|
||||
await self.bot.say("I could not find anyone with the user name/id of {}".format(user))
|
||||
except (IndexError, TypeError):
|
||||
await ctx.send("I could not find anyone with the user name/id of {}".format(user))
|
||||
return
|
||||
|
||||
# Now lets create our dictionary needed to create the image
|
||||
|
@ -181,11 +156,11 @@ class Osu:
|
|||
# Attempt to create our banner and upload that
|
||||
# If we can't find the images needed, or don't have permissions, just send a message instead
|
||||
try:
|
||||
banner = await images.create_banner(ctx.message.author, "Osu User Stats", fmt)
|
||||
await self.bot.upload(banner)
|
||||
banner = await utils.create_banner(ctx.message.author, "Osu User Stats", fmt)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
_fmt = "\n".join("{}: {}".format(k, r) for k, r in fmt.items())
|
||||
await self.bot.say("```\n{}```".format(_fmt))
|
||||
await ctx.send("```\n{}```".format(_fmt))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
from .utils import config
|
||||
from .utils import checks
|
||||
from .utils import images
|
||||
from . import utils
|
||||
|
||||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
import aiohttp
|
||||
|
||||
base_url = "https://api.owapi.net/api/v3/u/"
|
||||
BASE_URL = "https://api.owapi.net/api/v3/u/"
|
||||
# This is a list of the possible things that we may want to retrieve from the stats
|
||||
# The API returns something if it exists, and leaves it out of the data returned entirely if it does not
|
||||
# For example if you have not won with a character, wins will not exist in the list
|
||||
|
@ -15,7 +11,6 @@ base_url = "https://api.owapi.net/api/v3/u/"
|
|||
check_g_stats = ["eliminations", "deaths", 'kpd', 'wins', 'losses', 'time_played',
|
||||
'cards', 'damage_done', 'healing_done', 'multikills']
|
||||
check_o_stats = ['wins']
|
||||
MAX_RETRIES = 5
|
||||
|
||||
|
||||
class Overwatch:
|
||||
|
@ -23,29 +18,6 @@ class Overwatch:
|
|||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.headers = {"User-Agent": config.user_agent}
|
||||
self.session = aiohttp.ClientSession()
|
||||
|
||||
async def _request(self, payload, endpoint):
|
||||
"""Handles requesting to the API"""
|
||||
|
||||
# Format the URL we'll need based on the base_url, and the endpoint we want to hit
|
||||
url = "{}{}".format(base_url, endpoint)
|
||||
|
||||
# Attempt to connect up to our max retries
|
||||
for x in range(MAX_RETRIES):
|
||||
try:
|
||||
async with aiohttp.ClientSession(headers=self.headers) as session:
|
||||
async with session.get(url, params=payload) as r:
|
||||
# If we failed to connect, attempt again
|
||||
if r.status != 200:
|
||||
continue
|
||||
|
||||
data = await r.json()
|
||||
return data
|
||||
# If any error happened when making the request, attempt again
|
||||
except:
|
||||
continue
|
||||
|
||||
@commands.group(no_pm=True)
|
||||
async def ow(self):
|
||||
|
@ -55,29 +27,31 @@ class Overwatch:
|
|||
Capitalization also matters"""
|
||||
pass
|
||||
|
||||
@ow.command(name="stats", pass_context=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@ow.command(name="stats")
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def ow_stats(self, ctx, user: discord.Member = None, hero: str = ""):
|
||||
"""Prints out a basic overview of a member's stats
|
||||
Provide a hero after the member to get stats for that specific hero
|
||||
|
||||
EXAMPLE: !ow stats @OtherPerson Junkrat
|
||||
RESULT: Whether or not you should unfriend this person because they're a dirty rat"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
user = user or ctx.message.author
|
||||
r_filter = {'member_id': user.id}
|
||||
ow_stats = await config.get_content('overwatch', r_filter)
|
||||
ow_stats = await utils.get_content('overwatch', r_filter)
|
||||
|
||||
if ow_stats is None:
|
||||
await self.bot.say("I do not have this user's battletag saved!")
|
||||
await ctx.send("I do not have this user's battletag saved!")
|
||||
return
|
||||
# This API sometimes takes a while to look up information, so send a message saying we're processing
|
||||
await self.bot.say("Searching profile information....")
|
||||
|
||||
bt = ow_stats[0]['battletag']
|
||||
|
||||
if hero == "":
|
||||
# If no hero was provided, we just want the base stats for a player
|
||||
data = await self._request(None, "{}/stats".format(bt))
|
||||
url = BASE_URL + "{}/stats".format(bt)
|
||||
data = await utils.request(url)
|
||||
region = [x for x in data.keys() if data[x] is not None][0]
|
||||
stats = data[region]['stats']['quickplay']
|
||||
|
||||
|
@ -86,8 +60,8 @@ class Overwatch:
|
|||
else:
|
||||
# If there was a hero provided, search for a user's data on that hero
|
||||
hero = hero.lower().replace('-', '')
|
||||
endpoint = "{}/heroes".format(bt)
|
||||
data = await self._request(None, endpoint)
|
||||
url = BASE_URL + "{}/heroes".format(bt)
|
||||
data = await utils.request(url)
|
||||
|
||||
region = [x for x in data.keys() if data[x] is not None][0]
|
||||
stats = data[region]['heroes']['stats']['quickplay'].get(hero)
|
||||
|
@ -95,7 +69,7 @@ class Overwatch:
|
|||
if stats is None:
|
||||
fmt = "I couldn't find data with that hero, make sure that is a valid hero, " \
|
||||
"otherwise {} has never used the hero {} before!".format(user.display_name, hero)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
return
|
||||
|
||||
# Same list comprehension as before
|
||||
|
@ -104,55 +78,57 @@ class Overwatch:
|
|||
for k, r in stats['hero_stats'].items():
|
||||
output_data.append((k.title().replace("_", " "), r))
|
||||
try:
|
||||
banner = await images.create_banner(user, "Overwatch", output_data)
|
||||
await self.bot.upload(banner)
|
||||
banner = await utils.create_banner(user, "Overwatch", output_data)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
fmt = "\n".join("{}: {}".format(k, r) for k, r in output_data)
|
||||
await self.bot.say("Overwatch stats for {}: ```py\n{}```".format(user.name, fmt))
|
||||
await ctx.send("Overwatch stats for {}: ```py\n{}```".format(user.name, fmt))
|
||||
|
||||
@ow.command(pass_context=True, name="add")
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add(self, ctx, bt: str):
|
||||
"""Saves your battletag for looking up information
|
||||
|
||||
EXAMPLE: !ow add Username#1234
|
||||
RESULT: Your battletag is now saved"""
|
||||
await ctx.message.channel.trigger_typing()
|
||||
|
||||
# Battletags are normally provided like name#id
|
||||
# However the API needs this to be a -, so repliace # with - if it exists
|
||||
bt = bt.replace("#", "-")
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
|
||||
# This API sometimes takes a while to look up information, so send a message saying we're processing
|
||||
await self.bot.say("Looking up your profile information....")
|
||||
await ctx.send("Looking up your profile information....")
|
||||
# All we're doing here is ensuring that the status is 200 when looking up someone's general information
|
||||
# If it's not, let them know exactly how to format their tag
|
||||
endpoint = "{}/stats".format(bt)
|
||||
data = await self._request(None, endpoint)
|
||||
url = BASE_URL + "{}/stats".format(bt)
|
||||
data = await utils.request(url)
|
||||
if data is None:
|
||||
await self.bot.say("Profile does not exist! Battletags are picky, "
|
||||
"format needs to be `user#xxxx`. Capitalization matters")
|
||||
return
|
||||
await ctx.send("Profile does not exist! Battletags are picky, "
|
||||
"format needs to be `user#xxxx`. Capitalization matters")
|
||||
return
|
||||
|
||||
# Now just save the battletag
|
||||
entry = {'member_id': ctx.message.author.id, 'battletag': bt}
|
||||
update = {'battletag': bt}
|
||||
# Try adding this first, if that fails, update the saved entry
|
||||
if not await config.add_content('overwatch', entry, r_filter):
|
||||
await config.update_content('overwatch', update, r_filter)
|
||||
await self.bot.say("I have just saved your battletag {}".format(ctx.message.author.mention))
|
||||
if not await utils.add_content('overwatch', entry, r_filter):
|
||||
await utils.update_content('overwatch', update, r_filter)
|
||||
await ctx.send("I have just saved your battletag {}".format(ctx.message.author.mention))
|
||||
|
||||
@ow.command(pass_context=True, name="delete", aliases=['remove'])
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def delete(self, ctx):
|
||||
"""Removes your battletag from the records
|
||||
|
||||
EXAMPLE: !ow delete
|
||||
RESULT: Your battletag is no longer saved"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await config.remove_content('overwatch', r_filter):
|
||||
await self.bot.say("I no longer have your battletag saved {}".format(ctx.message.author.mention))
|
||||
if await utils.remove_content('overwatch', r_filter):
|
||||
await ctx.send("I no longer have your battletag saved {}".format(ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say("I don't even have your battletag saved {}".format(ctx.message.author.mention))
|
||||
await ctx.send("I don't even have your battletag saved {}".format(ctx.message.author.mention))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -4,11 +4,11 @@ from . import utils
|
|||
|
||||
import re
|
||||
import glob
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import discord
|
||||
import inspect
|
||||
import aiohttp
|
||||
import pendulum
|
||||
import asyncio
|
||||
|
||||
|
||||
class Owner:
|
||||
|
@ -19,7 +19,7 @@ class Owner:
|
|||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def motd_push(self, *, message):
|
||||
async def motd_push(self, ctx, *, message):
|
||||
"""Used to push a new message to the message of the day"""
|
||||
date = pendulum.utcnow().to_date_string()
|
||||
r_filter = {'date': date}
|
||||
|
@ -28,15 +28,14 @@ class Owner:
|
|||
# I should be managing this myself, more than one should not be sent in a day
|
||||
if await utils.add_content('motd', entry, r_filter):
|
||||
await utils.update_content('motd', entry, r_filter)
|
||||
await self.bot.say("New motd update for {}!".format(date))
|
||||
await ctx.send("New motd update for {}!".format(date))
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def debug(self, ctx, *, code : str):
|
||||
async def debug(self, ctx, *, code: str):
|
||||
"""Evaluates code."""
|
||||
code = code.strip('` ')
|
||||
python = '```py\n{}\n```'
|
||||
result = None
|
||||
|
||||
env = {
|
||||
'bot': self.bot,
|
||||
|
@ -54,41 +53,41 @@ class Owner:
|
|||
if inspect.isawaitable(result):
|
||||
result = await result
|
||||
except Exception as e:
|
||||
await self.bot.say(python.format(type(e).__name__ + ': ' + str(e)))
|
||||
await ctx.send(python.format(type(e).__name__ + ': ' + str(e)))
|
||||
return
|
||||
try:
|
||||
await self.bot.say(python.format(result))
|
||||
await ctx.send(python.format(result))
|
||||
except discord.HTTPException:
|
||||
await self.bot.say("Result is too long for me to send")
|
||||
await ctx.send("Result is too long for me to send")
|
||||
except:
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def shutdown(self, ctx):
|
||||
"""Shuts the bot down"""
|
||||
fmt = 'Shutting down, I will miss you {0.author.name}'
|
||||
await self.bot.say(fmt.format(ctx.message))
|
||||
await ctx.send(fmt.format(ctx.message))
|
||||
await self.bot.logout()
|
||||
await self.bot.close()
|
||||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def name(self, newNick: str):
|
||||
async def name(self, ctx, newNick: str):
|
||||
"""Changes the bot's name"""
|
||||
await self.bot.edit_profile(username=newNick)
|
||||
await self.bot.say('Changed username to ' + newNick)
|
||||
await ctx.send('Changed username to ' + newNick)
|
||||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def status(self, *, status: str):
|
||||
async def status(self, ctx, *, status: str):
|
||||
"""Changes the bot's 'playing' status"""
|
||||
await self.bot.change_status(discord.Game(name=status, type=0))
|
||||
await self.bot.say("Just changed my status to '{0}'!".format(status))
|
||||
await ctx.send("Just changed my status to '{0}'!".format(status))
|
||||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def load(self, *, module: str):
|
||||
async def load(self, ctx, *, module: str):
|
||||
"""Loads a module"""
|
||||
|
||||
# Do this because I'm too lazy to type cogs.module
|
||||
|
@ -99,14 +98,14 @@ class Owner:
|
|||
# This try catch will catch errors such as syntax errors in the module we are loading
|
||||
try:
|
||||
self.bot.load_extension(module)
|
||||
await self.bot.say("I have just loaded the {} module".format(module))
|
||||
await ctx.send("I have just loaded the {} module".format(module))
|
||||
except Exception as error:
|
||||
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
|
||||
await self.bot.say(fmt.format(type(error).__name__, error))
|
||||
await ctx.send(fmt.format(type(error).__name__, error))
|
||||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def unload(self, *, module: str):
|
||||
async def unload(self, ctx, *, module: str):
|
||||
"""Unloads a module"""
|
||||
|
||||
# Do this because I'm too lazy to type cogs.module
|
||||
|
@ -115,11 +114,11 @@ class Owner:
|
|||
module = "cogs.{}".format(module)
|
||||
|
||||
self.bot.unload_extension(module)
|
||||
await self.bot.say("I have just unloaded the {} module".format(module))
|
||||
await ctx.send("I have just unloaded the {} module".format(module))
|
||||
|
||||
@commands.command()
|
||||
@commands.check(utils.is_owner)
|
||||
async def reload(self, *, module: str):
|
||||
async def reload(self, ctx, *, module: str):
|
||||
"""Reloads a module"""
|
||||
|
||||
# Do this because I'm too lazy to type cogs.module
|
||||
|
@ -131,10 +130,10 @@ class Owner:
|
|||
# This try block will catch errors such as syntax errors in the module we are loading
|
||||
try:
|
||||
self.bot.load_extension(module)
|
||||
await self.bot.say("I have just reloaded the {} module".format(module))
|
||||
await ctx.send("I have just reloaded the {} module".format(module))
|
||||
except Exception as error:
|
||||
fmt = 'An error occurred while processing this request: ```py\n{}: {}\n```'
|
||||
await self.bot.say(fmt.format(type(error).__name__, error))
|
||||
await ctx.send(fmt.format(type(error).__name__, error))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
117
cogs/picarto.py
117
cogs/picarto.py
|
@ -11,7 +11,7 @@ from discord.ext import commands
|
|||
from . import utils
|
||||
|
||||
log = logging.getLogger()
|
||||
base_url = 'https://ptvappapi.picarto.tv'
|
||||
BASE_URL = 'https://ptvappapi.picarto.tv'
|
||||
|
||||
# This is a public key for use, I don't care if this is seen
|
||||
key = '03e26294-b793-11e5-9a41-005056984bd4'
|
||||
|
@ -23,10 +23,9 @@ async def online_users():
|
|||
# It is more efficent on their end to make a query for all online users, and base checks off that
|
||||
# In place of requesting for /channel and checking if that is online currently, for each channel
|
||||
# This method is in place to just return all online_users
|
||||
url = '{}/online/all?key={}'.format(base_url, key)
|
||||
with aiohttp.ClientSession(headers={"User-Agent": utils.user_agent}) as s:
|
||||
async with s.get(url) as response:
|
||||
return await response.json()
|
||||
url = BASE_URL + '/online/all'
|
||||
payload = {'key': key}
|
||||
return await utils.request(url, payload=payload)
|
||||
except:
|
||||
return {}
|
||||
|
||||
|
@ -64,24 +63,24 @@ class Picarto:
|
|||
user = re.search("(?<=picarto.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if check_online(online_users_list, user):
|
||||
for server_id in result['servers']:
|
||||
for guild_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
if server is None:
|
||||
guild = self.bot.get_guild(guild_id)
|
||||
if guild is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
guild_alerts = await utils.get_content('server_alerts', {'server_id': guild_id})
|
||||
try:
|
||||
channel_id = server_alerts[0]['channel_id']
|
||||
channel_id = guild_alerts[0]['channel_id']
|
||||
except (IndexError, TypeError):
|
||||
channel_id = server_id
|
||||
channel_id = guild_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = guild.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
fmt = "{} has just gone live! View their stream at {}".format(member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await channel.send(fmt)
|
||||
await utils.update_content('picarto', {'live': 1}, {'member_id': m_id})
|
||||
for m_id, result in old_online_users.items():
|
||||
# Get their url and their user based on that url
|
||||
|
@ -89,22 +88,25 @@ class Picarto:
|
|||
user = re.search("(?<=picarto.tv/)(.*)", url).group(1)
|
||||
# Check if they are online right now
|
||||
if not check_online(online_users_list, user):
|
||||
for server_id in result['servers']:
|
||||
for guild_id in result['servers']:
|
||||
# Get the channel to send the message to, based on the saved alert's channel
|
||||
server = self.bot.get_server(server_id)
|
||||
if server is None:
|
||||
guild = self.bot.get_guild(guild_id)
|
||||
if guild is None:
|
||||
continue
|
||||
server_alerts = await utils.get_content('server_alerts', {'server_id': server_id})
|
||||
guild_alerts = await utils.get_content('server_alerts', {'server_id': guild_id})
|
||||
try:
|
||||
channel_id = server_alerts[0]['channel_id']
|
||||
channel_id = guild_alerts[0]['channel_id']
|
||||
except (IndexError, TypeError):
|
||||
channel_id = server_id
|
||||
channel_id = guild_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = guild.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
fmt = "{} has just gone offline! Catch them next time they stream at {}".format(
|
||||
member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await channel.send(fmt)
|
||||
await utils.update_content('picarto', {'live': 0}, {'member_id': m_id})
|
||||
await asyncio.sleep(30)
|
||||
except Exception as e:
|
||||
|
@ -112,7 +114,7 @@ class Picarto:
|
|||
fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e)
|
||||
log.error(fmt)
|
||||
|
||||
@commands.group(pass_context=True, invoke_without_command=True, no_pm=True)
|
||||
@commands.group(invoke_without_command=True, no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def picarto(self, ctx, member: discord.Member = None):
|
||||
"""This command can be used to view Picarto stats about a certain member
|
||||
|
@ -124,15 +126,17 @@ class Picarto:
|
|||
r_filter = {'member_id': member.id}
|
||||
picarto_entry = await utils.get_content('picarto', r_filter)
|
||||
if picarto_entry is None:
|
||||
await self.bot.say("That user does not have a picarto url setup!")
|
||||
await ctx.send("That user does not have a picarto url setup!")
|
||||
return
|
||||
|
||||
member_url = picarto_entry[0]['picarto_url']
|
||||
|
||||
# Use regex to get the actual username so that we can make a request to the API
|
||||
stream = re.search("(?<=picarto.tv/)(.*)", member_url).group(1)
|
||||
url = '{}/channel/{}?key={}'.format(base_url, stream, key)
|
||||
async with self.session.get(url, headers=self.headers) as response:
|
||||
data = await response.json()
|
||||
url = BASE_URL + '/channel/{}'.format(stream)
|
||||
payload = {'key': key}
|
||||
|
||||
data = await utils.request(url, payload=payload)
|
||||
|
||||
# Not everyone has all these settings, so use this as a way to print information if it does, otherwise ignore it
|
||||
things_to_print = ['channel', 'commissions_enabled', 'is_nsfw', 'program', 'tablet', 'followers',
|
||||
|
@ -148,15 +152,15 @@ class Picarto:
|
|||
fmt2 = "\n".join(
|
||||
"\t{}: {}".format(i.title().replace("_", " "), result) for i, result in social_links.items())
|
||||
fmt = "{}\nSocial Links:\n{}".format(fmt, fmt2)
|
||||
await self.bot.say("Picarto stats for {}: ```\n{}```".format(member.display_name, fmt))
|
||||
await ctx.send("Picarto stats for {}: ```\n{}```".format(member.display_name, fmt))
|
||||
|
||||
@picarto.command(name='add', pass_context=True, no_pm=True)
|
||||
@picarto.command(name='add', no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add_picarto_url(self, ctx, url: str):
|
||||
"""Saves your user's picarto URL
|
||||
|
||||
EXAMPLE: !picarto add MyUsername
|
||||
RESULT: Your picarto stream is saved, and notifications should go to this server"""
|
||||
RESULT: Your picarto stream is saved, and notifications should go to this guild"""
|
||||
# This uses a lookbehind to check if picarto.tv exists in the url given
|
||||
# If it does, it matches picarto.tv/user and sets the url as that
|
||||
# Then (in the else) add https://www. to that
|
||||
|
@ -171,65 +175,64 @@ class Picarto:
|
|||
url = "https://www.picarto.tv/{}".format(url)
|
||||
else:
|
||||
url = "https://www.{}".format(url)
|
||||
|
||||
api_url = '{}/channel/{}?key={}'.format(base_url, re.search("https://www.picarto.tv/(.*)", url).group(1), key)
|
||||
|
||||
# Check if we can find a user with the provided information, if we can't just return
|
||||
async with self.session.get(api_url, headers=self.headers) as response:
|
||||
if not response.status == 200:
|
||||
await self.bot.say("That Picarto user does not exist! "
|
||||
"What would be the point of adding a nonexistant Picarto user? Silly")
|
||||
return
|
||||
channel = re.search("https://www.picarto.tv/(.*)", url).group(1)
|
||||
url = BASE_URL + '/channel/{}'.format(channel)
|
||||
payload = {'key': key}
|
||||
data = await utils.request(url, payload=payload)
|
||||
if not data:
|
||||
await ctx.send("That Picarto user does not exist! What would be the point of adding a nonexistant Picarto "
|
||||
"user? Silly")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
entry = {'picarto_url': url,
|
||||
'servers': [ctx.message.server.id],
|
||||
'servers': [ctx.message.guild.id],
|
||||
'notifications_on': 1,
|
||||
'live': 0,
|
||||
'member_id': ctx.message.author.id}
|
||||
if await utils.add_content('picarto', entry, r_filter):
|
||||
await self.bot.say(
|
||||
"I have just saved your Picarto URL {}, this server will now be notified when you go live".format(
|
||||
await ctx.send(
|
||||
"I have just saved your Picarto URL {}, this guild will now be notified when you go live".format(
|
||||
ctx.message.author.mention))
|
||||
else:
|
||||
await utils.update_content('picarto', {'picarto_url': url}, r_filter)
|
||||
await self.bot.say("I have just updated your Picarto URL")
|
||||
await ctx.send("I have just updated your Picarto URL")
|
||||
|
||||
@picarto.command(name='remove', aliases=['delete'], pass_context=True, no_pm=True)
|
||||
@picarto.command(name='remove', aliases=['delete'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def remove_picarto_url(self, ctx):
|
||||
"""Removes your picarto URL"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.remove_content('picarto', r_filter):
|
||||
await self.bot.say("I am no longer saving your picarto URL {}".format(ctx.message.author.mention))
|
||||
await ctx.send("I am no longer saving your picarto URL {}".format(ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I do not have your picarto URL added {}. You can save your picarto url with {}picarto add".format(
|
||||
ctx.message.author.mention, ctx.prefix))
|
||||
|
||||
@picarto.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@picarto.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify(self, ctx):
|
||||
"""This can be used to turn picarto notifications on or off
|
||||
Call this command by itself, to add this server to the list of servers to be notified
|
||||
Call this command by itself, to add this guild to the list of guilds to be notified
|
||||
|
||||
EXAMPLE: !picarto notify
|
||||
RESULT: This server will now be notified of you going live"""
|
||||
RESULT: This guild will now be notified of you going live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
result = await utils.get_content('picarto', r_filter)
|
||||
# Check if this user is saved at all
|
||||
if result is None:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I do not have your Picarto URL added {}. You can save your Picarto url with !picarto add".format(
|
||||
ctx.message.author.mention))
|
||||
# Then check if this server is already added as one to notify in
|
||||
elif ctx.message.server.id in result[0]['servers']:
|
||||
await self.bot.say("I am already set to notify in this server...")
|
||||
# Then check if this guild is already added as one to notify in
|
||||
elif ctx.message.guild.id in result[0]['servers']:
|
||||
await ctx.send("I am already set to notify in this guild...")
|
||||
else:
|
||||
await utils.update_content('picarto', {'servers': r.row['servers'].append(ctx.message.server.id)},
|
||||
r_filter)
|
||||
await utils.update_content('picarto', {'servers': r.row['servers'].append(ctx.message.guild.id)},
|
||||
r_filter)
|
||||
|
||||
@notify.command(name='on', aliases=['start,yes'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='on', aliases=['start,yes'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_on(self, ctx):
|
||||
"""Turns picarto notifications on
|
||||
|
@ -238,7 +241,7 @@ class Picarto:
|
|||
RESULT: Notifications are sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.update_content('picarto', {'notifications_on': 1}, r_filter)
|
||||
await self.bot.say("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
await ctx.send("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
ctx.message.author.mention))
|
||||
|
||||
@notify.command(name='off', aliases=['stop,no'], pass_context=True, no_pm=True)
|
||||
|
@ -250,7 +253,7 @@ class Picarto:
|
|||
RESULT: No more notifications sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.update_content('picarto', {'notifications_on': 0}, r_filter)
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I will not notify if you go live anymore {}, "
|
||||
"are you going to stream some lewd stuff you don't want people to see?~".format(
|
||||
ctx.message.author.mention))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from discord.ext import commands
|
||||
from .utils import config
|
||||
from .utils import checks
|
||||
import discord
|
||||
|
||||
from . import utils
|
||||
|
||||
import random
|
||||
import pendulum
|
||||
|
@ -27,13 +28,13 @@ class Raffle:
|
|||
async def check_raffles(self):
|
||||
# This is used to periodically check the current raffles, and see if they have ended yet
|
||||
# If the raffle has ended, we'll pick a winner from the entrants
|
||||
raffles = await config.get_content('raffles')
|
||||
raffles = await utils.get_content('raffles')
|
||||
|
||||
if raffles is None:
|
||||
return
|
||||
|
||||
for raffle in raffles:
|
||||
server = self.bot.get_server(raffle['server_id'])
|
||||
server = self.bot.get_guild(raffle['server_id'])
|
||||
|
||||
# Check to see if this cog can find the server in question
|
||||
if server is None:
|
||||
|
@ -74,23 +75,23 @@ class Raffle:
|
|||
# No matter which one of these matches were met, the raffle has ended and we want to remove it
|
||||
# We don't have to wait for it however, so create a task for it
|
||||
r_filter = {'id': raffle_id}
|
||||
self.bot.loop.create_task(config.remove_content('raffles', r_filter))
|
||||
self.bot.loop.create_task(utils.remove_content('raffles', r_filter))
|
||||
try:
|
||||
await self.bot.send_message(server, fmt)
|
||||
await server.send(fmt)
|
||||
except discord.Forbidden:
|
||||
pass
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def raffles(self, ctx):
|
||||
"""Used to print the current running raffles on the server
|
||||
|
||||
EXAMPLE: !raffles
|
||||
RESULT: A list of the raffles setup on this server"""
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
raffles = await config.get_content('raffles', r_filter)
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
raffles = await utils.get_content('raffles', r_filter)
|
||||
if raffles is None:
|
||||
await self.bot.say("There are currently no raffles setup on this server!")
|
||||
await ctx.send("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
||||
fmt = "\n\n".join("**Raffle:** {}\n**Title:** {}\n**Total Entrants:** {}\n**Ends:** {} UTC".format(
|
||||
|
@ -98,10 +99,10 @@ class Raffle:
|
|||
raffle['title'],
|
||||
len(raffle['entrants']),
|
||||
raffle['expires']) for num, raffle in enumerate(raffles))
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@commands.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def raffle(self, ctx, raffle_id: int = 0):
|
||||
"""Used to enter a raffle running on this server
|
||||
If there is more than one raffle running, provide an ID of the raffle you want to enter
|
||||
|
@ -110,12 +111,12 @@ class Raffle:
|
|||
RESULT: You've entered the first raffle!"""
|
||||
# Lets let people use 1 - (length of raffles) and handle 0 base ourselves
|
||||
raffle_id -= 1
|
||||
r_filter = {'server_id': ctx.message.server.id}
|
||||
r_filter = {'server_id': ctx.message.guild.id}
|
||||
author = ctx.message.author
|
||||
|
||||
raffles = await config.get_content('raffles', r_filter)
|
||||
raffles = await utils.get_content('raffles', r_filter)
|
||||
if raffles is None:
|
||||
await self.bot.say("There are currently no raffles setup on this server!")
|
||||
await ctx.send("There are currently no raffles setup on this server!")
|
||||
return
|
||||
|
||||
raffle_count = len(raffles)
|
||||
|
@ -125,38 +126,38 @@ class Raffle:
|
|||
entrants = raffles[0]['entrants']
|
||||
# Lets make sure that the user hasn't already entered the raffle
|
||||
if author.id in entrants:
|
||||
await self.bot.say("You have already entered this raffle!")
|
||||
await ctx.send("You have already entered this raffle!")
|
||||
return
|
||||
entrants.append(author.id)
|
||||
|
||||
# Since we have no good thing to filter things off of, lets use the internal rethinkdb id
|
||||
r_filter = {'id': raffles[0]['id']}
|
||||
update = {'entrants': entrants}
|
||||
await config.update_content('raffles', update, r_filter)
|
||||
await self.bot.say("{} you have just entered the raffle!".format(author.mention))
|
||||
await utils.update_content('raffles', update, r_filter)
|
||||
await ctx.send("{} you have just entered the raffle!".format(author.mention))
|
||||
# Otherwise, make sure the author gave a valid raffle_id
|
||||
elif raffle_id in range(raffle_count - 1):
|
||||
entrants = raffles[raffle_id]['entrants']
|
||||
|
||||
# Lets make sure that the user hasn't already entered the raffle
|
||||
if author.id in entrants:
|
||||
await self.bot.say("You have already entered this raffle!")
|
||||
await ctx.send("You have already entered this raffle!")
|
||||
return
|
||||
entrants.append(author.id)
|
||||
|
||||
# Since we have no good thing to filter things off of, lets use the internal rethinkdb id
|
||||
r_filter = {'id': raffles[raffle_id]['id']}
|
||||
update = {'entrants': entrants}
|
||||
await config.update_content('raffles', update, r_filter)
|
||||
await self.bot.say("{} you have just entered the raffle!".format(author.mention))
|
||||
await utils.update_content('raffles', update, r_filter)
|
||||
await ctx.send("{} you have just entered the raffle!".format(author.mention))
|
||||
else:
|
||||
fmt = "Please provide a valid raffle ID, as there are more than one setup on the server! " \
|
||||
"There are currently `{}` raffles running, use {}raffles to view the current running raffles".format(
|
||||
raffle_count, ctx.prefix)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@raffle.command(pass_context=True, no_pm=True, name='create', aliases=['start', 'begin', 'add'])
|
||||
@checks.custom_perms(kick_members=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def raffle_create(self, ctx):
|
||||
"""This is used in order to create a new server raffle
|
||||
|
||||
|
@ -164,16 +165,18 @@ class Raffle:
|
|||
RESULT: A follow-along for setting up a new raffle"""
|
||||
|
||||
author = ctx.message.author
|
||||
server = ctx.message.server
|
||||
server = ctx.message.guild
|
||||
channel = ctx.message.channel
|
||||
now = pendulum.utcnow()
|
||||
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Ready to start a new raffle! Please respond with the title you would like to use for this raffle!")
|
||||
|
||||
msg = await self.bot.wait_for_message(author=author, channel=channel, timeout=120)
|
||||
check = lambda m: m.author == author and m.channel == channel
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=120)
|
||||
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long! >:c")
|
||||
await ctx.send("You took too long! >:c")
|
||||
return
|
||||
|
||||
title = msg.content
|
||||
|
@ -181,13 +184,18 @@ class Raffle:
|
|||
fmt = "Alright, your new raffle will be titled:\n\n{}\n\nHow long would you like this raffle to run for? " \
|
||||
"The format should be [number] [length] for example, `2 days` or `1 hour` or `30 minutes` etc. " \
|
||||
"The minimum for this is 10 minutes, and the maximum is 3 months"
|
||||
await self.bot.say(fmt.format(title))
|
||||
await ctx.send(fmt.format(title))
|
||||
|
||||
# Our check to ensure that a proper length of time was passed
|
||||
check = lambda m: re.search("\d+ (minutes?|hours?|days?|weeks?|months?)", m.content.lower()) is not None
|
||||
msg = await self.bot.wait_for_message(author=author, channel=channel, timeout=120, check=check)
|
||||
def check(m):
|
||||
if m.author == author and m.channel == channel:
|
||||
return re.search("\d+ (minutes?|hours?|days?|weeks?|months?)", m.content.lower()) is not None
|
||||
else:
|
||||
return False
|
||||
msg = await self.bot.wait_for('message', timeout=120, check=check)
|
||||
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long! >:c")
|
||||
await ctx.send("You took too long! >:c")
|
||||
return
|
||||
|
||||
# Lets get the length provided, based on the number and type passed
|
||||
|
@ -197,28 +205,28 @@ class Raffle:
|
|||
|
||||
# Now lets ensure this meets our min/max
|
||||
if "minute" in term and (num < 10 or num > 129600):
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Length provided out of range! The minimum for this is 10 minutes, and the maximum is 3 months")
|
||||
return
|
||||
elif "hour" in term and num > 2160:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Length provided out of range! The minimum for this is 10 minutes, and the maximum is 3 months")
|
||||
return
|
||||
elif "day" in term and num > 90:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Length provided out of range! The minimum for this is 10 minutes, and the maximum is 3 months")
|
||||
return
|
||||
elif "week" in term and num > 12:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Length provided out of range! The minimum for this is 10 minutes, and the maximum is 3 months")
|
||||
return
|
||||
elif "month" in term and num > 3:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Length provided out of range! The minimum for this is 10 minutes, and the maximum is 3 months")
|
||||
return
|
||||
|
||||
# Pendulum only accepts the plural version of terms, lets make sure this is added
|
||||
term = term if term.endswith('s') else '{}s'.format(term)
|
||||
term = term if term.endswith('s') else term + 's'
|
||||
# If we're in the range, lets just pack this in a dictionary we can pass to set the time we want, then set that
|
||||
payload = {term: num}
|
||||
expires = now.add(**payload)
|
||||
|
@ -231,8 +239,8 @@ class Raffle:
|
|||
'server_id': server.id}
|
||||
|
||||
# We don't want to pass a filter to this, because we can have multiple raffles per server
|
||||
await config.add_content('raffles', entry)
|
||||
await self.bot.say("I have just saved your new raffle!")
|
||||
await utils.add_content('raffles', entry)
|
||||
await ctx.send("I have just saved your new raffle!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
169
cogs/roles.py
169
cogs/roles.py
|
@ -1,6 +1,7 @@
|
|||
from discord.ext import commands
|
||||
import discord
|
||||
from .utils import checks
|
||||
|
||||
from . import utils
|
||||
|
||||
import re
|
||||
import asyncio
|
||||
|
@ -12,8 +13,8 @@ class Roles:
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.group(aliases=['roles'], invoke_without_command=True, no_pm=True, pass_context=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.group(aliases=['roles'], invoke_without_command=True, no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def role(self, ctx):
|
||||
"""This command can be used to modify the roles on the server.
|
||||
Pass no subcommands and this will print the roles currently available on this server
|
||||
|
@ -22,10 +23,10 @@ class Roles:
|
|||
RESULT: A list of all your roles"""
|
||||
# Simply get a list of all roles in this server and send them
|
||||
server_roles = [role.name for role in ctx.message.server.roles if not role.is_everyone]
|
||||
await self.bot.say("Your server's roles are: ```\n{}```".format("\n".join(server_roles)))
|
||||
await ctx.send("Your server's roles are: ```\n{}```".format("\n".join(server_roles)))
|
||||
|
||||
@role.command(name='remove', pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(manage_roles=True)
|
||||
@role.command(name='remove', no_pm=True)
|
||||
@utils.custom_perms(manage_roles=True)
|
||||
async def remove_role(self, ctx):
|
||||
"""Use this to remove roles from a number of members
|
||||
|
||||
|
@ -33,33 +34,35 @@ class Roles:
|
|||
RESULT: A follow-along to remove the role(s) you want to, from these 3 members"""
|
||||
# No use in running through everything if the bot cannot manage roles
|
||||
if not ctx.message.server.me.permissions_in(ctx.message.channel).manage_roles:
|
||||
await self.bot.say("I can't manage roles in this server, do you not trust me? :c")
|
||||
await ctx.send("I can't manage roles in this server, do you not trust me? :c")
|
||||
return
|
||||
check = lambda m: m.author == ctx.message.author and m.channel == ctx.message.channel
|
||||
|
||||
server_roles = [role for role in ctx.message.server.roles if not role.is_everyone]
|
||||
# First get the list of all mentioned users
|
||||
members = ctx.message.mentions
|
||||
# If no users are mentioned, ask the author for a list of the members they want to remove the role from
|
||||
if len(members) == 0:
|
||||
await self.bot.say("Please provide the list of members you want to remove a role from")
|
||||
msg = await self.bot.wait_for_message(author=ctx.message.author, channel=ctx.message.channel)
|
||||
await ctx.send("Please provide the list of members you want to remove a role from")
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=60)
|
||||
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
if len(msg.mentions) == 0:
|
||||
await self.bot.say("I cannot remove a role from someone if you don't provide someone...")
|
||||
await ctx.send("I cannot remove a role from someone if you don't provide someone...")
|
||||
return
|
||||
# Override members if everything has gone alright, and then continue
|
||||
members = msg.mentions
|
||||
|
||||
# This allows the user to remove multiple roles from the list of users, if they want.
|
||||
await self.bot.say("Alright, please provide the roles you would like to remove from this member. "
|
||||
"Make sure the roles, if more than one is provided, are separate by commas. "
|
||||
"Here is a list of this server's roles:"
|
||||
"```\n{}```".format("\n".join([r.name for r in server_roles])))
|
||||
msg = await self.bot.wait_for_message(author=ctx.message.author, channel=ctx.message.channel)
|
||||
await ctx.send("Alright, please provide the roles you would like to remove from this member. "
|
||||
"Make sure the roles, if more than one is provided, are separate by commas. "
|
||||
"Here is a list of this server's roles:"
|
||||
"```\n{}```".format("\n".join([r.name for r in server_roles])))
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=60)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
|
||||
# Split the content based on commas, using regex so we can split if a space was not provided or if it was
|
||||
|
@ -73,17 +76,17 @@ class Roles:
|
|||
|
||||
# If no valid roles were given, let them know that and return
|
||||
if len(roles) == 0:
|
||||
await self.bot.say("Please provide a valid role next time!")
|
||||
await ctx.send("Please provide a valid role next time!")
|
||||
return
|
||||
|
||||
# Otherwise, remove the roles from each member given
|
||||
for member in members:
|
||||
await self.bot.remove_roles(member, *roles)
|
||||
await self.bot.say("I have just removed the following roles:```\n{}``` from the following members:"
|
||||
"```\n{}```".format("\n".join(role_names), "\n".join([m.display_name for m in members])))
|
||||
await ctx.send("I have just removed the following roles:```\n{}``` from the following members:"
|
||||
"```\n{}```".format("\n".join(role_names), "\n".join([m.display_name for m in members])))
|
||||
|
||||
@role.command(name='add', pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(manage_roles=True)
|
||||
@role.command(name='add', no_pm=True)
|
||||
@utils.custom_perms(manage_roles=True)
|
||||
async def add_role(self, ctx):
|
||||
"""Use this to add a role to multiple members.
|
||||
Provide the list of members, and I'll ask for the role
|
||||
|
@ -93,31 +96,32 @@ class Roles:
|
|||
RESULT: A follow along to add the roles you want to these 3"""
|
||||
# No use in running through everything if the bot cannot manage roles
|
||||
if not ctx.message.server.me.permissions_in(ctx.message.channel).manage_roles:
|
||||
await self.bot.say("I can't manage roles in this server, do you not trust me? :c")
|
||||
await ctx.send("I can't manage roles in this server, do you not trust me? :c")
|
||||
return
|
||||
check = lambda m: m.author == ctx.message.author and m.channel == ctx.message.channel
|
||||
|
||||
# This is exactly the same as removing roles, except we call add_roles instead.
|
||||
server_roles = [role for role in ctx.message.server.roles if not role.is_everyone]
|
||||
members = ctx.message.mentions
|
||||
if len(members) == 0:
|
||||
await self.bot.say("Please provide the list of members you want to add a role to")
|
||||
msg = await self.bot.wait_for_message(author=ctx.message.author, channel=ctx.message.channel)
|
||||
await ctx.send("Please provide the list of members you want to add a role to")
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=60)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
if len(msg.mentions) == 0:
|
||||
await self.bot.say("I cannot add a role to someone if you don't provide someone...")
|
||||
await ctx.send("I cannot add a role to someone if you don't provide someone...")
|
||||
return
|
||||
members = msg.mentions
|
||||
|
||||
await self.bot.say("Alright, please provide the roles you would like to add to this member. "
|
||||
"Make sure the roles, if more than one is provided, are separate by commas. "
|
||||
"Here is a list of this server's roles:"
|
||||
"```\n{}```".format("\n".join([r.name for r in server_roles])))
|
||||
await ctx.send("Alright, please provide the roles you would like to add to this member. "
|
||||
"Make sure the roles, if more than one is provided, are separate by commas. "
|
||||
"Here is a list of this server's roles:"
|
||||
"```\n{}```".format("\n".join([r.name for r in server_roles])))
|
||||
|
||||
msg = await self.bot.wait_for_message(author=ctx.message.author, channel=ctx.message.channel)
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=60)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
role_names = re.split(', ?', msg.content)
|
||||
roles = []
|
||||
|
@ -127,16 +131,16 @@ class Roles:
|
|||
roles.append(_role)
|
||||
|
||||
if len(roles) == 0:
|
||||
await self.bot.say("Please provide a valid role next time!")
|
||||
await ctx.send("Please provide a valid role next time!")
|
||||
return
|
||||
|
||||
for member in members:
|
||||
await self.bot.add_roles(member, *roles)
|
||||
await self.bot.say("I have just added the following roles:```\n{}``` to the following members:"
|
||||
"```\n{}```".format("\n".join(role_names), "\n".join([m.display_name for m in members])))
|
||||
await member.add_roles(*roles)
|
||||
await ctx.send("I have just added the following roles:```\n{}``` to the following members:"
|
||||
"```\n{}```".format("\n".join(role_names), "\n".join([m.display_name for m in members])))
|
||||
|
||||
@role.command(name='delete', pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(manage_roles=True)
|
||||
@role.command(name='delete', no_pm=True)
|
||||
@utils.custom_perms(manage_roles=True)
|
||||
async def delete_role(self, ctx, *, role: discord.Role = None):
|
||||
"""This command can be used to delete one of the roles from the server
|
||||
|
||||
|
@ -144,34 +148,39 @@ class Roles:
|
|||
RESULT: No more role called StupidRole"""
|
||||
# No use in running through everything if the bot cannot manage roles
|
||||
if not ctx.message.server.me.permissions_in(ctx.message.channel).manage_roles:
|
||||
await self.bot.say("I can't delete roles in this server, do you not trust me? :c")
|
||||
await ctx.send("I can't delete roles in this server, do you not trust me? :c")
|
||||
return
|
||||
|
||||
# If no role was given, get the current roles on the server and ask which ones they'd like to remove
|
||||
if role is None:
|
||||
server_roles = [role for role in ctx.message.server.roles if not role.is_everyone]
|
||||
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Which role would you like to remove from the server? Here is a list of this server's roles:"
|
||||
"```\n{}```".format("\n".join([r.name for r in server_roles])))
|
||||
|
||||
# For this method we're only going to delete one role at a time
|
||||
# This check attempts to find a role based on the content provided, if it can't find one it returns None
|
||||
# We can use that fact to simply use just that as our check
|
||||
check = lambda m: discord.utils.get(server_roles, name=m.content)
|
||||
msg = await self.bot.wait_for_message(author=ctx.message.author, channel=ctx.message.channel, check=check)
|
||||
def check(m):
|
||||
if m.author == ctx.message.author and m.channel == ctx.message.channel:
|
||||
return discord.utils.get(server_roles, name=m.content) is not None
|
||||
else:
|
||||
return False
|
||||
|
||||
msg = await self.bot.wait_for('message', timeout=60, check=check)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
# If we have gotten here, based on our previous check, we know that the content provided is a valid role.
|
||||
# Due to that, no need for any error checking here
|
||||
role = discord.utils.get(server_roles, name=msg.content)
|
||||
|
||||
await self.bot.delete_role(ctx.message.server, role)
|
||||
await self.bot.say("I have just removed the role {} from this server".format(role.name))
|
||||
await role.delete()
|
||||
await ctx.send("I have just removed the role {} from this server".format(role.name))
|
||||
|
||||
@role.command(name='create', pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(manage_roles=True)
|
||||
@role.command(name='create', no_pm=True)
|
||||
@utils.custom_perms(manage_roles=True)
|
||||
async def create_role(self, ctx):
|
||||
"""This command can be used to create a new role for this server
|
||||
A prompt will follow asking what settings you would like for this new role
|
||||
|
@ -181,7 +190,7 @@ class Roles:
|
|||
RESULT: A follow along in order to create a new role"""
|
||||
# No use in running through everything if the bot cannot create the role
|
||||
if not ctx.message.server.me.permissions_in(ctx.message.channel).manage_roles:
|
||||
await self.bot.say("I can't create roles in this server, do you not trust me? :c")
|
||||
await ctx.send("I can't create roles in this server, do you not trust me? :c")
|
||||
return
|
||||
|
||||
# Save a couple variables that will be used repeatedly
|
||||
|
@ -190,48 +199,64 @@ class Roles:
|
|||
channel = ctx.message.channel
|
||||
|
||||
# A couple checks that will be used in the wait_for_message's
|
||||
num_separated_check = lambda m: re.search("(\d(, ?| )?|[nN]one)", m.content) is not None
|
||||
yes_no_check = lambda m: re.search("(yes|no)", m.content.lower()) is not None
|
||||
members_check = lambda m: len(m.mentions) > 0
|
||||
def num_seperated_check(m):
|
||||
if m.author == author and m.channel == channel:
|
||||
return re.search("(\d(, ?| )?|[nN]one)", m.content) is not None
|
||||
else:
|
||||
return False
|
||||
|
||||
def yes_no_check(m):
|
||||
if m.author == author and m.channel == channel:
|
||||
return re.search("(yes|no)", m.content.lower()) is not None
|
||||
else:
|
||||
return False
|
||||
|
||||
def members_check(m):
|
||||
if m.author == author and m.channel == channel:
|
||||
return len(m.mentions) > 0
|
||||
else:
|
||||
return False
|
||||
|
||||
author_check = lambda m: m.author == author and m.channel == channel
|
||||
|
||||
# Start the checks for the role, get the name of the role first
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Alright! I'm ready to create a new role, please respond with the name of the role you want to create")
|
||||
msg = await self.bot.wait_for_message(timeout=60.0, author=author, channel=channel)
|
||||
msg = await self.bot.wait_for('message', timeout=60.0, check=author_check)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
name = msg.content
|
||||
|
||||
# Print a list of all the permissions available, then ask for which ones need to be active on this new role
|
||||
all_perms = [p for p in dir(discord.Permissions) if isinstance(getattr(discord.Permissions, p), property)]
|
||||
fmt = "\n".join("{}) {}".format(i, perm) for i, perm in enumerate(all_perms))
|
||||
await self.bot.say("Sounds fancy! Here is a list of all the permissions available. Please respond with just "
|
||||
"the numbers, seperated by commas, of the permissions you want this role to have.\n"
|
||||
"```\n{}```".format(fmt))
|
||||
await ctx.send("Sounds fancy! Here is a list of all the permissions available. Please respond with just "
|
||||
"the numbers, seperated by commas, of the permissions you want this role to have.\n"
|
||||
"```\n{}```".format(fmt))
|
||||
# For this we're going to give a couple extra minutes before we timeout
|
||||
# as it might take a bit to figure out which permissions they want
|
||||
msg = await self.bot.wait_for_message(timeout=180.0, author=author, channel=channel, check=num_separated_check)
|
||||
msg = await self.bot.wait_for('message', timeout=180.0, check=num_seperated_check)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
|
||||
# Check if any integer's were provided that are within the length of the list of permissions
|
||||
num_permissions = [int(i) for i in re.split(' ?,?', msg.content) if i.isdigit() and int(i) < len(all_perms)]
|
||||
|
||||
# Check if this role should be in a separate section on the sidebard, i.e. hoisted
|
||||
await self.bot.say("Do you want this role to be in a separate section on the sidebar? (yes or no)")
|
||||
msg = await self.bot.wait_for_message(timeout=60.0, author=author, channel=channel, check=yes_no_check)
|
||||
await ctx.send("Do you want this role to be in a separate section on the sidebar? (yes or no)")
|
||||
msg = await self.bot.wait_for('message', timeout=60.0, check=yes_no_check)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
hoist = True if msg.content.lower() == "yes" else False
|
||||
|
||||
# Check if this role should be able to be mentioned
|
||||
await self.bot.say("Do you want this role to be mentionable? (yes or no)")
|
||||
msg = await self.bot.wait_for_message(timeout=60.0, author=author, channel=channel, check=yes_no_check)
|
||||
await ctx.send("Do you want this role to be mentionable? (yes or no)")
|
||||
msg = await self.bot.wait_for('message', timeout=60.0, check=yes_no_check)
|
||||
if msg is None:
|
||||
await self.bot.say("You took too long. I'm impatient, don't make me wait")
|
||||
await ctx.send("You took too long. I'm impatient, don't make me wait")
|
||||
return
|
||||
mentionable = True if msg.content.lower() == "yes" else False
|
||||
|
||||
|
@ -248,21 +273,21 @@ class Roles:
|
|||
'mentionable': mentionable
|
||||
}
|
||||
# Create the role, and wait a second, sometimes it goes too quickly and we get a role with 'new role' to print
|
||||
role = await self.bot.create_role(server, **payload)
|
||||
role = await server.create_role(**payload)
|
||||
await asyncio.sleep(1)
|
||||
await self.bot.say("We did it! You just created the new role {}\nIf you want to add this role"
|
||||
" to some people, mention them now".format(role.name))
|
||||
msg = await self.bot.wait_for_message(timeout=60.0, author=author, channel=channel, check=members_check)
|
||||
await ctx.send("We did it! You just created the new role {}\nIf you want to add this role"
|
||||
" to some people, mention them now".format(role.name))
|
||||
msg = await self.bot.wait_for('message', timeout=60.0, check=members_check)
|
||||
# There's no need to mention the users, so don't send a failure message if they didn't, just return
|
||||
if msg is None:
|
||||
return
|
||||
|
||||
# Otherwise members were mentioned, add the new role to them now
|
||||
for member in msg.mentions:
|
||||
await self.bot.add_roles(member, role)
|
||||
await member.add_roles(role)
|
||||
|
||||
fmt = "\n".join(m.display_name for m in msg.mentions)
|
||||
await self.bot.say("I have just added the role {} to: ```\n{}```".format(name, fmt))
|
||||
await ctx.send("I have just added the role {} to: ```\n{}```".format(name, fmt))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -12,29 +12,14 @@ class Stats:
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
def find_command(self, command):
|
||||
cmd = None
|
||||
|
||||
for part in command.split():
|
||||
try:
|
||||
if cmd is None:
|
||||
cmd = self.bot.commands.get(part)
|
||||
else:
|
||||
cmd = cmd.commands.get(part)
|
||||
except AttributeError:
|
||||
cmd = None
|
||||
break
|
||||
|
||||
return cmd
|
||||
|
||||
@commands.command(no_pm=True, pass_context=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def serverinfo(self, ctx):
|
||||
"""Provides information about the server
|
||||
|
||||
EXAMPLE: !serverinfo
|
||||
RESULT: Information about your server!"""
|
||||
server = ctx.message.server
|
||||
server = ctx.message.guild
|
||||
# Create our embed that we'll use for the information
|
||||
embed = discord.Embed(title=server.name, description="Created on: {}".format(server.created_at.date()))
|
||||
|
||||
|
@ -57,26 +42,23 @@ class Stats:
|
|||
embed.add_field(name='Channels', value='{} text, {} voice'.format(len(text_channels), len(voice_channels)))
|
||||
embed.add_field(name='Owner', value=server.owner.display_name)
|
||||
|
||||
# Add the shard ID
|
||||
embed.set_footer(text="Server is on shard: {}/{}".format(self.bot.shard_id+1, self.bot.shard_count))
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
await self.bot.say(embed=embed)
|
||||
|
||||
@commands.group(no_pm=True)
|
||||
@commands.group(no_pm=True, pass_context=False)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def command(self):
|
||||
pass
|
||||
|
||||
@command.command(no_pm=True, pass_context=True, name="stats")
|
||||
@command.command(no_pm=True, name="stats")
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def command_stats(self, ctx, *, command):
|
||||
"""This command can be used to view some usage stats about a specific command
|
||||
|
||||
EXAMPLE: !command stats play
|
||||
RESULT: The realization that this is the only reason people use me ;-;"""
|
||||
cmd = self.find_command(command)
|
||||
cmd = self.bot.get_command(command)
|
||||
if cmd is None:
|
||||
await self.bot.say("`{}` is not a valid command".format(command))
|
||||
await ctx.send("`{}` is not a valid command".format(command))
|
||||
return
|
||||
|
||||
r_filter = {'command': cmd.qualified_name}
|
||||
|
@ -84,12 +66,12 @@ class Stats:
|
|||
try:
|
||||
command_stats = command_stats[0]
|
||||
except TypeError:
|
||||
await self.bot.say("That command has never been used! You know I worked hard on that! :c")
|
||||
await ctx.send("That command has never been used! You know I worked hard on that! :c")
|
||||
return
|
||||
|
||||
total_usage = command_stats['total_usage']
|
||||
member_usage = command_stats['member_usage'].get(ctx.message.author.id, 0)
|
||||
server_usage = command_stats['server_usage'].get(ctx.message.server.id, 0)
|
||||
server_usage = command_stats['server_usage'].get(ctx.message.guild.id, 0)
|
||||
|
||||
try:
|
||||
data = [("Command Name", cmd.qualified_name),
|
||||
|
@ -97,16 +79,16 @@ class Stats:
|
|||
("Your Usage", member_usage),
|
||||
("This Server's Usage", server_usage)]
|
||||
banner = await utils.create_banner(ctx.message.author, "Command Stats", data)
|
||||
await self.bot.upload(banner)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
fmt = "The command {} has been used a total of {} times\n" \
|
||||
"{} times on this server\n" \
|
||||
"It has been ran by you, {}, {} times".format(cmd.qualified_name, total_usage, server_usage,
|
||||
ctx.message.author.display_name, member_usage)
|
||||
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@command.command(no_pm=True, pass_context=True, name="leaderboard")
|
||||
@command.command(no_pm=True, name="leaderboard")
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def command_leaderboard(self, ctx, option="server"):
|
||||
"""This command can be used to print a leaderboard of commands
|
||||
|
@ -132,26 +114,26 @@ class Stats:
|
|||
try:
|
||||
top_5 = [(data[0], data[1]) for data in sorted_stats[:5]]
|
||||
banner = await utils.create_banner(ctx.message.author, "Your command usage", top_5)
|
||||
await self.bot.upload(banner)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
top_5 = "\n".join("{}: {}".format(data[0], data[1]) for data in sorted_stats[:5])
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Your top {} most used commands are:\n```\n{}```".format(len(sorted_stats[:5]), top_5))
|
||||
elif re.search('server', option):
|
||||
# This is exactly the same as above, except server usage instead of member usage
|
||||
server = ctx.message.server
|
||||
server = ctx.message.guild
|
||||
command_stats = await utils.get_content('command_usage')
|
||||
stats = {data['command']: data['server_usage'].get(server.id) for data in command_stats
|
||||
if data['server_usage'].get(server.id, 0) > 0}
|
||||
sorted_stats = sorted(stats.items(), key=lambda x: x[1], reverse=True)
|
||||
|
||||
top_5 = "\n".join("{}: {}".format(data[0], data[1]) for data in sorted_stats[:5])
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"This server's top {} most used commands are:\n```\n{}```".format(len(sorted_stats[:5]), top_5))
|
||||
else:
|
||||
await self.bot.say("That is not a valid option, valid options are: `server` or `me`")
|
||||
await ctx.send("That is not a valid option, valid options are: `server` or `me`")
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def mostboops(self, ctx):
|
||||
"""Shows the person you have 'booped' the most, as well as how many times
|
||||
|
@ -161,14 +143,14 @@ class Stats:
|
|||
r_filter = {'member_id': ctx.message.author.id}
|
||||
boops = await utils.get_content('boops', r_filter)
|
||||
if boops is None:
|
||||
await self.bot.say("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
await ctx.send("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
# Just to make this easier, just pay attention to the boops data, now that we have the right entry
|
||||
boops = boops[0]['boops']
|
||||
|
||||
# First get a list of the ID's of all members in this server, for use in list comprehension
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
server_member_ids = [member.id for member in ctx.message.guild.members]
|
||||
# Then get a sorted list, based on the amount of times they've booped the member
|
||||
# Reverse needs to be true, as we want it to go from highest to lowest
|
||||
sorted_boops = sorted(boops.items(), key=lambda x: x[1], reverse=True)
|
||||
|
@ -179,10 +161,10 @@ class Stats:
|
|||
most_id, most_boops = sorted_boops[0]
|
||||
|
||||
member = discord.utils.find(lambda m: m.id == most_id, self.bot.get_all_members())
|
||||
await self.bot.say("{0} you have booped {1} the most amount of times, coming in at {2} times".format(
|
||||
await ctx.send("{0} you have booped {1} the most amount of times, coming in at {2} times".format(
|
||||
ctx.message.author.mention, member.display_name, most_boops))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def listboops(self, ctx):
|
||||
"""Lists all the users you have booped and the amount of times
|
||||
|
@ -192,31 +174,31 @@ class Stats:
|
|||
r_filter = {'member_id': ctx.message.author.id}
|
||||
boops = await utils.get_content('boops', r_filter)
|
||||
if boops is None:
|
||||
await self.bot.say("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
await ctx.send("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention))
|
||||
return
|
||||
|
||||
# Just to make this easier, just pay attention to the boops data, now that we have the right entry
|
||||
boops = boops[0]['boops']
|
||||
|
||||
# Same concept as the mostboops method
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
server_member_ids = [member.id for member in ctx.message.guild.members]
|
||||
booped_members = {m_id: amt for m_id, amt in boops.items() if m_id in server_member_ids}
|
||||
sorted_booped_members = sorted(booped_members.items(), key=lambda k: k[1], reverse=True)
|
||||
# Now we only want the first 10 members, so splice this list
|
||||
sorted_booped_members = sorted_booped_members[:10]
|
||||
|
||||
try:
|
||||
output = [("{0.display_name}".format(ctx.message.server.get_member(m_id)), amt)
|
||||
output = [("{0.display_name}".format(ctx.message.guild.get_member(m_id)), amt)
|
||||
for m_id, amt in sorted_booped_members]
|
||||
banner = await utils.create_banner(ctx.message.author, "Your booped victims", output)
|
||||
await self.bot.upload(banner)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
output = "\n".join(
|
||||
"{0.display_name}: {1} times".format(ctx.message.server.get_member(m_id), amt) for
|
||||
"{0.display_name}: {1} times".format(ctx.message.guild.get_member(m_id), amt) for
|
||||
m_id, amt in sorted_booped_members)
|
||||
await self.bot.say("You have booped:```\n{}```".format(output))
|
||||
await ctx.send("You have booped:```\n{}```".format(output))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def leaderboard(self, ctx):
|
||||
"""Prints a leaderboard of everyone in the server's battling record
|
||||
|
@ -224,7 +206,7 @@ class Stats:
|
|||
EXAMPLE: !leaderboard
|
||||
RESULT: A leaderboard of this server's battle records"""
|
||||
# Create a list of the ID's of all members in this server, for comparison to the records saved
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
server_member_ids = [member.id for member in ctx.message.guild.members]
|
||||
battles = await utils.get_content('battle_records')
|
||||
battles = [battle for battle in battles if battle['member_id'] in server_member_ids]
|
||||
|
||||
|
@ -235,16 +217,16 @@ class Stats:
|
|||
for x in sorted_members:
|
||||
member_id = x['member_id']
|
||||
rating = x['rating']
|
||||
member = ctx.message.server.get_member(member_id)
|
||||
member = ctx.message.guild.get_member(member_id)
|
||||
output.append("{} (Rating: {})".format(member.display_name, rating))
|
||||
|
||||
try:
|
||||
pages = utils.Pages(self.bot, message=ctx.message, entries=output)
|
||||
await pages.paginate()
|
||||
except utils.CannotPaginate as e:
|
||||
await self.bot.say(str(e))
|
||||
await ctx.send(str(e))
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def stats(self, ctx, member: discord.Member = None):
|
||||
"""Prints the battling stats for you, or the user provided
|
||||
|
@ -259,11 +241,11 @@ class Stats:
|
|||
|
||||
# Make a list comprehension to just check if the user has battled
|
||||
if len([entry for entry in all_members if entry['member_id'] == member.id]) == 0:
|
||||
await self.bot.say("That user has not battled yet!")
|
||||
await ctx.send("That user has not battled yet!")
|
||||
return
|
||||
|
||||
# Same concept as the leaderboard
|
||||
server_member_ids = [member.id for member in ctx.message.server.members]
|
||||
server_member_ids = [member.id for member in ctx.message.guild.members]
|
||||
server_members = [stats for stats in all_members if stats['member_id'] in server_member_ids]
|
||||
sorted_server_members = sorted(server_members, key=lambda x: x['rating'], reverse=True)
|
||||
sorted_all_members = sorted(all_members, key=lambda x: x['rating'], reverse=True)
|
||||
|
@ -282,12 +264,12 @@ class Stats:
|
|||
fmt = [('Record', record), ('Server Rank', '{}/{}'.format(server_rank, len(server_members))),
|
||||
('Overall Rank', '{}/{}'.format(total_rank, len(all_members))), ('Rating', rating)]
|
||||
banner = await utils.create_banner(member, title, fmt)
|
||||
await self.bot.upload(banner)
|
||||
await ctx.send(file=banner)
|
||||
except (FileNotFoundError, discord.Forbidden):
|
||||
fmt = 'Stats for {}:\n\tRecord: {}\n\tServer Rank: {}/{}\n\tOverall Rank: {}/{}\n\tRating: {}'
|
||||
fmt = fmt.format(member.display_name, record, server_rank, len(server_members), total_rank,
|
||||
len(all_members), rating)
|
||||
await self.bot.say('```\n{}```'.format(fmt))
|
||||
await ctx.send('```\n{}```'.format(fmt))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
63
cogs/tags.py
63
cogs/tags.py
|
@ -1,8 +1,9 @@
|
|||
from discord.ext import commands
|
||||
from .utils import config
|
||||
from .utils import checks
|
||||
import re
|
||||
|
||||
from discord.ext import commands
|
||||
|
||||
from . import utils
|
||||
|
||||
|
||||
class Tags:
|
||||
"""This class contains all the commands for custom tags"""
|
||||
|
@ -10,39 +11,39 @@ class Tags:
|
|||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command(pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.command(no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def tags(self, ctx):
|
||||
"""Prints all the custom tags that this server currently has
|
||||
|
||||
EXAMPLE: !tags
|
||||
RESULT: All tags setup on this server"""
|
||||
tags = await config.get_content('tags', {'server_id': ctx.message.server.id})
|
||||
tags = await utils.get_content('tags', {'server_id': ctx.message.guild.id})
|
||||
# Simple generator that adds a tag to the list to print, if the tag is for this server
|
||||
try:
|
||||
fmt = "\n".join("{}".format(tag['tag']) for tag in tags)
|
||||
await self.bot.say('```\n{}```'.format(fmt))
|
||||
await ctx.send('```\n{}```'.format(fmt))
|
||||
except TypeError:
|
||||
await self.bot.say("There are not tags setup on this server!")
|
||||
await ctx.send("There are not tags setup on this server!")
|
||||
|
||||
@commands.group(pass_context=True, invoke_without_command=True, no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.group(invoke_without_command=True, no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def tag(self, ctx, *, tag: str):
|
||||
"""This can be used to call custom tags
|
||||
The format to call a custom tag is !tag <tag>
|
||||
|
||||
EXAMPLE: !tag butts
|
||||
RESULT: Whatever you setup for the butts tag!!"""
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.server.id) & (row['tag'] == tag)
|
||||
tags = await config.get_content('tags', r_filter)
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag)
|
||||
tags = await utils.get_content('tags', r_filter)
|
||||
if tags is None:
|
||||
await self.bot.say('That tag does not exist!')
|
||||
await ctx.send('That tag does not exist!')
|
||||
return
|
||||
# We shouldn't ever have two tags of the same name, so just get the first result
|
||||
await self.bot.say("\u200B{}".format(tags[0]['result']))
|
||||
await ctx.send("\u200B{}".format(tags[0]['result']))
|
||||
|
||||
@tag.command(name='add', aliases=['create', 'start'], pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
@tag.command(name='add', aliases=['create', 'start'], no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def add_tag(self, ctx, *, result: str):
|
||||
"""Use this to add a new tag that can be used in this server
|
||||
Format to add a tag is !tag add <tag> - <result>
|
||||
|
@ -56,43 +57,43 @@ class Tags:
|
|||
tag_result = match.group(2).strip()
|
||||
# Next two checks are just to ensure there was a valid match found
|
||||
except AttributeError:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Please provide the format for the tag in: {}tag add <tag> - <result>".format(ctx.prefix))
|
||||
return
|
||||
# If our regex failed to find the content (aka they provided the wrong format)
|
||||
if len(tag) == 0 or len(tag_result) == 0:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"Please provide the format for the tag in: {}tag add <tag> - <result>".format(ctx.prefix))
|
||||
return
|
||||
|
||||
# Make sure the tag created does not mention everyone/here
|
||||
if '@everyone' in tag_result or '@here' in tag_result:
|
||||
await self.bot.say("You cannot create a tag that mentions everyone!")
|
||||
await ctx.send("You cannot create a tag that mentions everyone!")
|
||||
return
|
||||
entry = {'server_id': ctx.message.server.id, 'tag': tag, 'result': tag_result}
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.server.id) & (row['tag'] == tag)
|
||||
entry = {'server_id': ctx.message.guild.id, 'tag': tag, 'result': tag_result}
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag)
|
||||
# Try to create new entry first, if that fails (it already exists) then we update it
|
||||
if await config.add_content('tags', entry, r_filter):
|
||||
await self.bot.say(
|
||||
if await utils.add_content('tags', entry, r_filter):
|
||||
await ctx.send(
|
||||
"I have just added the tag `{0}`! You can call this tag by entering !tag {0}".format(tag))
|
||||
else:
|
||||
await config.update_content('tags', entry, r_filter)
|
||||
await self.bot.say(
|
||||
await utils.update_content('tags', entry, r_filter)
|
||||
await ctx.send(
|
||||
"I have just updated the tag `{0}`! You can call this tag by entering !tag {0}".format(tag))
|
||||
|
||||
@tag.command(name='delete', aliases=['remove', 'stop'], pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
@tag.command(name='delete', aliases=['remove', 'stop'], no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def del_tag(self, ctx, *, tag: str):
|
||||
"""Use this to remove a tag from use for this server
|
||||
Format to delete a tag is !tag delete <tag>
|
||||
|
||||
EXAMPLE: !tag delete stupid_tag
|
||||
RESULT: Deletes that stupid tag"""
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.server.id) & (row['tag'] == tag)
|
||||
if await config.remove_content('tags', r_filter):
|
||||
await self.bot.say('I have just removed the tag `{}`'.format(tag))
|
||||
r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag)
|
||||
if await utils.remove_content('tags', r_filter):
|
||||
await ctx.send('I have just removed the tag `{}`'.format(tag))
|
||||
else:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"The tag {} does not exist! You can't remove something if it doesn't exist...".format(tag))
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
from discord.ext import commands
|
||||
import discord
|
||||
|
||||
from .utils import config
|
||||
from .utils import checks
|
||||
from .utils import utilities
|
||||
from . import utils
|
||||
|
||||
import re
|
||||
import random
|
||||
|
@ -110,8 +108,8 @@ class TicTacToe:
|
|||
# Return whoever is x's so that we know who is going first
|
||||
return self.boards[server_id].challengers['x']
|
||||
|
||||
@commands.group(pass_context=True, aliases=['tic', 'tac', 'toe'], no_pm=True, invoke_without_command=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@commands.group(aliases=['tic', 'tac', 'toe'], no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def tictactoe(self, ctx, *, option: str):
|
||||
"""Updates the current server's tic-tac-toe board
|
||||
You obviously need to be one of the players to use this
|
||||
|
@ -121,15 +119,15 @@ class TicTacToe:
|
|||
EXAMPLE: !tictactoe middle top
|
||||
RESULT: Your piece is placed in the very top space, in the middle"""
|
||||
player = ctx.message.author
|
||||
board = self.boards.get(ctx.message.server.id)
|
||||
board = self.boards.get(ctx.message.guild.id)
|
||||
# Need to make sure the board exists before allowing someone to play
|
||||
if not board:
|
||||
await self.bot.say("There are currently no Tic-Tac-Toe games setup!")
|
||||
await ctx.send("There are currently no Tic-Tac-Toe games setup!")
|
||||
return
|
||||
# Now just make sure the person can play, this will fail if o's are up and x tries to play
|
||||
# Or if someone else entirely tries to play
|
||||
if not board.can_play(player):
|
||||
await self.bot.say("You cannot play right now!")
|
||||
await ctx.send("You cannot play right now!")
|
||||
return
|
||||
|
||||
# Search for the positions in the option given, the actual match doesn't matter, just need to check if it exists
|
||||
|
@ -141,14 +139,14 @@ class TicTacToe:
|
|||
|
||||
# Just a bit of logic to ensure nothing that doesn't make sense is given
|
||||
if top and bottom:
|
||||
await self.bot.say("That is not a valid location! Use some logic, come on!")
|
||||
await ctx.send("That is not a valid location! Use some logic, come on!")
|
||||
return
|
||||
if left and right:
|
||||
await self.bot.say("That is not a valid location! Use some logic, come on!")
|
||||
await ctx.send("That is not a valid location! Use some logic, come on!")
|
||||
return
|
||||
# Make sure at least something was given
|
||||
if not top and not bottom and not left and not right and not middle:
|
||||
await self.bot.say("Please provide a valid location to play!")
|
||||
await ctx.send("Please provide a valid location to play!")
|
||||
return
|
||||
|
||||
x = 0
|
||||
|
@ -181,7 +179,7 @@ class TicTacToe:
|
|||
# board.update will handle which letter is placed
|
||||
# If it returns false however, then someone has already played in that spot and nothing was updated
|
||||
if not board.update(x, y):
|
||||
await self.bot.say("Someone has already played there!")
|
||||
await ctx.send("Someone has already played there!")
|
||||
return
|
||||
# Next check if there's a winner
|
||||
winner = board.check()
|
||||
|
@ -189,25 +187,25 @@ class TicTacToe:
|
|||
# Get the loser based on whether or not the winner is x's
|
||||
# If the winner is x's, the loser is o's...obviously, and vice-versa
|
||||
loser = board.challengers['x'] if board.challengers['x'] != winner else board.challengers['o']
|
||||
await self.bot.say("{} has won this game of TicTacToe, better luck next time {}".format(winner.display_name,
|
||||
loser.display_name))
|
||||
await ctx.send("{} has won this game of TicTacToe, better luck next time {}".format(winner.display_name,
|
||||
loser.display_name))
|
||||
# Handle updating ratings based on the winner and loser
|
||||
await utilities.update_records('tictactoe', winner, loser)
|
||||
await utils.update_records('tictactoe', winner, loser)
|
||||
# This game has ended, delete it so another one can be made
|
||||
del self.boards[ctx.message.server.id]
|
||||
del self.boards[ctx.message.guild.id]
|
||||
else:
|
||||
# If no one has won, make sure the game is not full. If it has, delete the board and say it was a tie
|
||||
if board.full():
|
||||
await self.bot.say("This game has ended in a tie!")
|
||||
del self.boards[ctx.message.server.id]
|
||||
await ctx.send("This game has ended in a tie!")
|
||||
del self.boards[ctx.message.guild.id]
|
||||
# If no one has won, and the game has not ended in a tie, print the new updated board
|
||||
else:
|
||||
player_turn = board.challengers.get('x') if board.X_turn else board.challengers.get('o')
|
||||
fmt = str(board) + "\n{} It is now your turn to play!".format(player_turn.display_name)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@tictactoe.command(name='start', aliases=['challenge', 'create'], pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(send_messages=True)
|
||||
@tictactoe.command(name='start', aliases=['challenge', 'create'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def start_game(self, ctx, player2: discord.Member):
|
||||
"""Starts a game of tictactoe with another player
|
||||
|
||||
|
@ -216,32 +214,32 @@ class TicTacToe:
|
|||
player1 = ctx.message.author
|
||||
# For simplicities sake, only allow one game on a server at a time.
|
||||
# Things can easily get confusing (on the server's end) if we allow more than one
|
||||
if self.boards.get(ctx.message.server.id) is not None:
|
||||
await self.bot.say("Sorry but only one Tic-Tac-Toe game can be running per server!")
|
||||
if self.boards.get(ctx.message.guild.id) is not None:
|
||||
await ctx.send("Sorry but only one Tic-Tac-Toe game can be running per server!")
|
||||
return
|
||||
# Make sure we're not being challenged, I always win anyway
|
||||
if player2 == ctx.message.server.me:
|
||||
await self.bot.say("You want to play? Alright lets play.\n\nI win, so quick you didn't even notice it.")
|
||||
if player2 == ctx.message.guild.me:
|
||||
await ctx.send("You want to play? Alright lets play.\n\nI win, so quick you didn't even notice it.")
|
||||
return
|
||||
if player2 == player1:
|
||||
await self.bot.say("You can't play yourself, I won't allow it. Go find some friends")
|
||||
await ctx.send("You can't play yourself, I won't allow it. Go find some friends")
|
||||
return
|
||||
|
||||
# Create the board and return who has been decided to go first
|
||||
x_player = self.create(ctx.message.server.id, player1, player2)
|
||||
x_player = self.create(ctx.message.guild.id, player1, player2)
|
||||
fmt = "A tictactoe game has just started between {} and {}".format(player1.display_name, player2.display_name)
|
||||
# Print the board too just because
|
||||
fmt += str(self.boards[ctx.message.server.id])
|
||||
fmt += str(self.boards[ctx.message.guild.id])
|
||||
|
||||
# We don't need to do anything weird with assigning x_player to something
|
||||
# it is already a member object, just use it
|
||||
fmt += "I have decided at random, and {} is going to be x's this game. It is your turn first! " \
|
||||
"Use the {}tictactoe command, and a position, to choose where you want to play"\
|
||||
"Use the {}tictactoe command, and a position, to choose where you want to play" \
|
||||
.format(x_player.display_name, ctx.prefix)
|
||||
await self.bot.say(fmt)
|
||||
await ctx.send(fmt)
|
||||
|
||||
@tictactoe.command(name='delete', aliases=['stop', 'remove', 'end'], pass_context=True, no_pm=True)
|
||||
@checks.custom_perms(kick_members=True)
|
||||
@tictactoe.command(name='delete', aliases=['stop', 'remove', 'end'], no_pm=True)
|
||||
@utils.custom_perms(kick_members=True)
|
||||
async def stop_game(self, ctx):
|
||||
"""Force stops a game of tictactoe
|
||||
This should realistically only be used in a situation like one player leaves
|
||||
|
@ -249,12 +247,12 @@ class TicTacToe:
|
|||
|
||||
EXAMPLE: !tictactoe stop
|
||||
RESULT: No more tictactoe!"""
|
||||
if self.boards.get(ctx.message.server.id) is None:
|
||||
await self.bot.say("There are no tictactoe games running on this server!")
|
||||
if self.boards.get(ctx.message.guild.id) is None:
|
||||
await ctx.send("There are no tictactoe games running on this server!")
|
||||
return
|
||||
|
||||
del self.boards[ctx.message.server.id]
|
||||
await self.bot.say("I have just stopped the game of TicTacToe, a new should be able to be started now!")
|
||||
del self.boards[ctx.message.guild.id]
|
||||
await ctx.send("I have just stopped the game of TicTacToe, a new should be able to be started now!")
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
|
|
@ -5,7 +5,6 @@ from . import utils
|
|||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import json
|
||||
import re
|
||||
import rethinkdb as r
|
||||
import traceback
|
||||
|
@ -69,12 +68,12 @@ class Twitch:
|
|||
channel_id = server_id
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = server.get_member(m_id)
|
||||
if member is None:
|
||||
continue
|
||||
|
||||
fmt = "{} has just gone live! View their stream at {}".format(member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await channel.send(fmt)
|
||||
await utils.update_content('twitch', {'live': 1}, {'member_id': m_id})
|
||||
for m_id, result in online_users.items():
|
||||
# Get their url and their user based on that url
|
||||
|
@ -93,10 +92,10 @@ class Twitch:
|
|||
channel_id = server_alerts[0].get('channel_id')
|
||||
channel = self.bot.get_channel(channel_id)
|
||||
# Get the member that has just gone live
|
||||
member = discord.utils.get(server.members, id=m_id)
|
||||
member = server.get_member(m_id)
|
||||
fmt = "{} has just gone offline! Catch them next time they stream at {}".format(
|
||||
member.display_name, url)
|
||||
await self.bot.send_message(channel, fmt)
|
||||
await channel.send(fmt)
|
||||
await utils.update_content('twitch', {'live': 0}, {'member_id': m_id})
|
||||
await asyncio.sleep(30)
|
||||
except Exception as e:
|
||||
|
@ -104,7 +103,7 @@ class Twitch:
|
|||
fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e)
|
||||
log.error(fmt)
|
||||
|
||||
@commands.group(no_pm=True, invoke_without_command=True, pass_context=True)
|
||||
@commands.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def twitch(self, ctx, *, member: discord.Member = None):
|
||||
"""Use this command to check the twitch info of a user
|
||||
|
@ -116,7 +115,7 @@ class Twitch:
|
|||
|
||||
result = await utils.get_content('twitch', {'member_id': member.id})
|
||||
if result is None:
|
||||
await self.bot.say("{} has not saved their twitch URL yet!".format(member.name))
|
||||
await ctx.send("{} has not saved their twitch URL yet!".format(member.name))
|
||||
return
|
||||
|
||||
result = result[0]
|
||||
|
@ -131,9 +130,9 @@ class Twitch:
|
|||
fmt += "\nStatus: {}".format(data['status'])
|
||||
fmt += "\nFollowers: {}".format(data['followers'])
|
||||
fmt += "\nURL: {}".format(url)
|
||||
await self.bot.say("```\n{}```".format(fmt))
|
||||
await ctx.send("```\n{}```".format(fmt))
|
||||
|
||||
@twitch.command(name='add', pass_context=True, no_pm=True)
|
||||
@twitch.command(name='add', no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def add_twitch_url(self, ctx, url: str):
|
||||
"""Saves your user's twitch URL
|
||||
|
@ -156,16 +155,15 @@ class Twitch:
|
|||
url = "https://www.{}".format(url)
|
||||
|
||||
# Try to find the channel provided, we'll get a 404 response if it does not exist
|
||||
with aiohttp.ClientSession() as s:
|
||||
async with s.get(url) as response:
|
||||
if not response.status == 200:
|
||||
await self.bot.say("That twitch user does not exist! "
|
||||
"What would be the point of adding a nonexistant twitch user? Silly")
|
||||
return
|
||||
status = await utils.request(url, attr='status')
|
||||
if not status == 200:
|
||||
await ctx.send("That twitch user does not exist! "
|
||||
"What would be the point of adding a nonexistant twitch user? Silly")
|
||||
return
|
||||
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
entry = {'twitch_url': url,
|
||||
'servers': [ctx.message.server.id],
|
||||
'servers': [ctx.message.guild.id],
|
||||
'notifications_on': 1,
|
||||
'live': 0,
|
||||
'member_id': ctx.message.author.id}
|
||||
|
@ -176,9 +174,9 @@ class Twitch:
|
|||
# Assuming they're not live, and notifications should be on
|
||||
if not await utils.add_content('twitch', entry, r_filter):
|
||||
await utils.update_content('twitch', update, r_filter)
|
||||
await self.bot.say("I have just saved your twitch url {}".format(ctx.message.author.mention))
|
||||
await ctx.send("I have just saved your twitch url {}".format(ctx.message.author.mention))
|
||||
|
||||
@twitch.command(name='remove', aliases=['delete'], pass_context=True, no_pm=True)
|
||||
@twitch.command(name='remove', aliases=['delete'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def remove_twitch_url(self, ctx):
|
||||
"""Removes your twitch URL
|
||||
|
@ -188,9 +186,9 @@ class Twitch:
|
|||
# Just try to remove it, if it doesn't exist, nothing is going to happen
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
await utils.remove_content('twitch', r_filter)
|
||||
await self.bot.say("I am no longer saving your twitch URL {}".format(ctx.message.author.mention))
|
||||
await ctx.send("I am no longer saving your twitch URL {}".format(ctx.message.author.mention))
|
||||
|
||||
@twitch.group(pass_context=True, no_pm=True, invoke_without_command=True)
|
||||
@twitch.group(no_pm=True, invoke_without_command=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify(self, ctx):
|
||||
"""This can be used to modify notification settings for your twitch user
|
||||
|
@ -202,17 +200,17 @@ class Twitch:
|
|||
result = await utils.get_content('twitch', r_filter)
|
||||
# Check if this user is saved at all
|
||||
if result is None:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I do not have your twitch URL added {}. You can save your twitch url with !twitch add".format(
|
||||
ctx.message.author.mention))
|
||||
# Then check if this server is already added as one to notify in
|
||||
elif ctx.message.server.id in result[0]['servers']:
|
||||
await self.bot.say("I am already set to notify in this server...")
|
||||
elif ctx.message.guild.id in result[0]['servers']:
|
||||
await ctx.send("I am already set to notify in this server...")
|
||||
else:
|
||||
await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.server.id)}, r_filter)
|
||||
await self.bot.say("This server will now be notified if you go live")
|
||||
await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.guild.id)}, r_filter)
|
||||
await ctx.send("This server will now be notified if you go live")
|
||||
|
||||
@notify.command(name='on', aliases=['start,yes'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='on', aliases=['start,yes'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_on(self, ctx):
|
||||
"""Turns twitch notifications on
|
||||
|
@ -221,12 +219,12 @@ class Twitch:
|
|||
RESULT: Notifications will be sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.update_content('twitch', {"notifications_on": 1}, r_filter):
|
||||
await self.bot.say("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
await ctx.send("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format(
|
||||
ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say("I can't notify if you go live if I don't know your twitch URL yet!")
|
||||
await ctx.send("I can't notify if you go live if I don't know your twitch URL yet!")
|
||||
|
||||
@notify.command(name='off', aliases=['stop,no'], pass_context=True, no_pm=True)
|
||||
@notify.command(name='off', aliases=['stop,no'], no_pm=True)
|
||||
@utils.custom_perms(send_messages=True)
|
||||
async def notify_off(self, ctx):
|
||||
"""Turns twitch notifications off
|
||||
|
@ -235,12 +233,12 @@ class Twitch:
|
|||
RESULT: Notifications will not be sent when you go live"""
|
||||
r_filter = {'member_id': ctx.message.author.id}
|
||||
if await utils.update_content('twitch', {"notifications_on": 1}, r_filter):
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I will not notify if you go live anymore {}, "
|
||||
"are you going to stream some lewd stuff you don't want people to see?~".format(
|
||||
ctx.message.author.mention))
|
||||
else:
|
||||
await self.bot.say(
|
||||
await ctx.send(
|
||||
"I mean, I'm already not going to notify anyone, because I don't have your twitch URL saved...")
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from .cards import Deck
|
||||
from .checks import is_owner, custom_perms, is_pm, db_check
|
||||
from .checks import is_owner, custom_perms, db_check
|
||||
from .config import *
|
||||
from .utilities import *
|
||||
from .images import create_banner
|
||||
|
|
|
@ -24,9 +24,10 @@ async def db_check():
|
|||
except r.errors.ReqlDriverError:
|
||||
print("Cannot connect to the RethinkDB instance with the following information: {}".format(db_opts))
|
||||
|
||||
print("The RethinkDB instance you have setup may be down, otherwise please ensure you setup a"\
|
||||
" RethinkDB instance, and you have provided the correct database information in config.yml")
|
||||
print("The RethinkDB instance you have setup may be down, otherwise please ensure you setup a"
|
||||
" RethinkDB instance, and you have provided the correct database information in config.yml")
|
||||
quit()
|
||||
return
|
||||
|
||||
# Get the current databases and check if the one we need is there
|
||||
dbs = await r.db_list().run(conn)
|
||||
|
@ -48,6 +49,7 @@ async def db_check():
|
|||
await r.table_create(table).run(conn)
|
||||
print("Done checking tables!")
|
||||
|
||||
|
||||
def is_owner(ctx):
|
||||
return ctx.message.author.id in config.owner_ids
|
||||
|
||||
|
@ -80,10 +82,3 @@ def custom_perms(**perms):
|
|||
|
||||
predicate.perms = perms
|
||||
return commands.check(predicate)
|
||||
|
||||
|
||||
def is_pm():
|
||||
def predicate(ctx):
|
||||
return ctx.message.channel.is_private
|
||||
|
||||
return commands.check(predicate)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import asyncio
|
||||
import discord
|
||||
|
||||
|
||||
class CannotPaginate(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Pages:
|
||||
"""Implements a paginator that queries the user for the
|
||||
pagination interface.
|
||||
|
@ -13,6 +15,7 @@ class Pages:
|
|||
If the user does not reply within 2 minutes, the pagination
|
||||
interface exits automatically.
|
||||
"""
|
||||
|
||||
def __init__(self, bot, *, message, entries, per_page=10):
|
||||
self.bot = bot
|
||||
self.entries = entries
|
||||
|
@ -30,12 +33,12 @@ class Pages:
|
|||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
|
||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page ),
|
||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page),
|
||||
('\N{BLACK SQUARE FOR STOP}', self.stop_pages),
|
||||
('\N{INFORMATION SOURCE}', self.show_help),
|
||||
]
|
||||
|
||||
server = self.message.server
|
||||
server = self.message.guild
|
||||
if server is not None:
|
||||
self.permissions = self.message.channel.permissions_for(server.me)
|
||||
else:
|
||||
|
@ -59,11 +62,11 @@ class Pages:
|
|||
|
||||
if not self.paginating:
|
||||
self.embed.description = '\n'.join(p)
|
||||
return await self.bot.send_message(self.message.channel, embed=self.embed)
|
||||
return await self.message.channel.send(embed=self.embed)
|
||||
|
||||
if not first:
|
||||
self.embed.description = '\n'.join(p)
|
||||
await self.bot.edit_message(self.message, embed=self.embed)
|
||||
await self.message.edit(embed=self.embed)
|
||||
return
|
||||
|
||||
# verify we can actually use the pagination session
|
||||
|
@ -76,7 +79,7 @@ class Pages:
|
|||
p.append('')
|
||||
p.append('Confused? React with \N{INFORMATION SOURCE} for more info.')
|
||||
self.embed.description = '\n'.join(p)
|
||||
self.message = await self.bot.send_message(self.message.channel, embed=self.embed)
|
||||
self.message = await self.message.channel.send(embed=self.embed)
|
||||
for (reaction, _) in self.reaction_emojis:
|
||||
if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'):
|
||||
# no |<< or >>| buttons if we only have two pages
|
||||
|
@ -84,7 +87,7 @@ class Pages:
|
|||
# it from the default set
|
||||
continue
|
||||
try:
|
||||
await self.bot.add_reaction(self.message, reaction)
|
||||
await self.message.add_reaction(reaction)
|
||||
except discord.NotFound:
|
||||
# If the message isn't found, we don't care about clearing anything
|
||||
return
|
||||
|
@ -116,40 +119,45 @@ class Pages:
|
|||
async def numbered_page(self):
|
||||
"""lets you type a page number to go to"""
|
||||
to_delete = []
|
||||
to_delete.append(await self.bot.send_message(self.message.channel, 'What page do you want to go to?'))
|
||||
msg = await self.bot.wait_for_message(author=self.author, channel=self.message.channel,
|
||||
check=lambda m: m.content.isdigit(), timeout=30.0)
|
||||
to_delete.append(await self.message.channel.send('What page do you want to go to?'))
|
||||
def check(m):
|
||||
if m.author == self.author and m.channel == self.message.channel:
|
||||
return m.content.isdigit()
|
||||
else:
|
||||
return False
|
||||
msg = await self.bot.wait_for('message', check=check, timeout=30.0)
|
||||
if msg is not None:
|
||||
page = int(msg.content)
|
||||
to_delete.append(msg)
|
||||
if page != 0 and page <= self.maximum_pages:
|
||||
await self.show_page(page)
|
||||
else:
|
||||
to_delete.append(await self.bot.say('Invalid page given. (%s/%s)' % (page, self.maximum_pages)))
|
||||
to_delete.append(await self.message.channel.send(
|
||||
'Invalid page given. (%s/%s)' % (page, self.maximum_pages)))
|
||||
await asyncio.sleep(5)
|
||||
else:
|
||||
to_delete.append(await self.bot.send_message(self.message.channel, 'Took too long.'))
|
||||
to_delete.append(await self.message.channel.send('Took too long.'))
|
||||
await asyncio.sleep(5)
|
||||
|
||||
try:
|
||||
await self.bot.delete_messages(to_delete)
|
||||
await self.message.channel.delete_messages(to_delete)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def show_help(self):
|
||||
"""shows this message"""
|
||||
e = discord.Embed()
|
||||
messages = ['Welcome to the interactive paginator!\n']
|
||||
messages.append('This interactively allows you to see pages of text by navigating with ' \
|
||||
'reactions. They are as follows:\n')
|
||||
messages = ['Welcome to the interactive paginator!\n',
|
||||
'This interactively allows you to see pages of text by navigating with '
|
||||
'reactions. They are as follows:\n']
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
messages.append('%s %s' % (emoji, func.__doc__))
|
||||
|
||||
e.description = '\n'.join(messages)
|
||||
e.colour = 0x738bd7 # blurple
|
||||
e.colour = 0x738bd7 # blurple
|
||||
e.set_footer(text='We were on page %s before this message.' % self.current_page)
|
||||
await self.bot.edit_message(self.message, embed=e)
|
||||
await self.message.edit(embed=e)
|
||||
|
||||
async def go_back_to_current_page():
|
||||
await asyncio.sleep(60.0)
|
||||
|
@ -159,11 +167,11 @@ class Pages:
|
|||
|
||||
async def stop_pages(self):
|
||||
"""stops the interactive pagination session"""
|
||||
await self.bot.delete_message(self.message)
|
||||
await self.message.delete()
|
||||
self.paginating = False
|
||||
|
||||
def react_check(self, reaction, user):
|
||||
if user is None or user.id != self.author.id:
|
||||
if user is None or user.id != self.author.id or reaction.message != self.message:
|
||||
return False
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
|
@ -177,19 +185,19 @@ class Pages:
|
|||
await self.show_page(start_page, first=True)
|
||||
|
||||
while self.paginating:
|
||||
react = await self.bot.wait_for_reaction(message=self.message, check=self.react_check, timeout=120.0)
|
||||
react = await self.bot.wait_for('reaction', check=self.react_check, timeout=120.0)
|
||||
if react is None:
|
||||
self.paginating = False
|
||||
try:
|
||||
await self.bot.clear_reactions(self.message)
|
||||
await self.message.clear_reactions()
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
break
|
||||
|
||||
try:
|
||||
await self.bot.remove_reaction(self.message, react.reaction.emoji, react.user)
|
||||
await self.message.remove_reaction(react.reaction.emoji, react.user)
|
||||
except:
|
||||
pass # can't remove it so don't bother doing so
|
||||
pass # can't remove it so don't bother doing so
|
||||
|
||||
await self.match()
|
||||
|
|
|
@ -5,6 +5,7 @@ import inspect
|
|||
from . import config
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def convert_to_jpeg(pfile):
|
||||
# Open the file given
|
||||
img = Image.open(pfile)
|
||||
|
@ -16,6 +17,7 @@ def convert_to_jpeg(pfile):
|
|||
new_file.seek(0)
|
||||
return new_file
|
||||
|
||||
|
||||
def get_all_commands(bot):
|
||||
"""Returns a list of all command names for the bot"""
|
||||
# First lets create a set of all the parent names
|
||||
|
@ -31,6 +33,7 @@ def get_all_commands(bot):
|
|||
|
||||
return all_commands
|
||||
|
||||
|
||||
def get_subcommands(command):
|
||||
yield command.qualified_name
|
||||
try:
|
||||
|
@ -40,33 +43,9 @@ def get_subcommands(command):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
def find_command(bot, command):
|
||||
"""Finds a command (be it parent or sub command) based on string given"""
|
||||
# This method ensures the command given is valid. We need to loop through commands
|
||||
# As bot.commands only includes parent commands
|
||||
# So we are splitting the command in parts, looping through the commands
|
||||
# And getting the subcommand based on the next part
|
||||
# If we try to access commands of a command that isn't a group
|
||||
# We'll hit an AttributeError, meaning an invalid command was given
|
||||
# If we loop through and don't find anything, cmd will still be None
|
||||
# And we'll report an invalid was given as well
|
||||
cmd = None
|
||||
|
||||
for part in command.split():
|
||||
try:
|
||||
if cmd is None:
|
||||
cmd = bot.commands.get(part)
|
||||
else:
|
||||
cmd = cmd.commands.get(part)
|
||||
except AttributeError:
|
||||
cmd = None
|
||||
break
|
||||
|
||||
return cmd
|
||||
|
||||
async def download_image(url):
|
||||
"""Returns a file-like object based on the URL provided"""
|
||||
headers = {'User-Agent': config.user_agent}
|
||||
# Simply read the image, to get the bytes
|
||||
bts = await request(url, attr='read')
|
||||
if bts is None:
|
||||
|
@ -76,10 +55,12 @@ async def download_image(url):
|
|||
image = BytesIO(bts)
|
||||
return image
|
||||
|
||||
|
||||
async def request(url, *, headers=None, payload=None, method='GET', attr='json'):
|
||||
# Make sure our User Agent is what's set, and ensure it's sent even if no headers are passed
|
||||
if headers == None:
|
||||
if headers is None:
|
||||
headers = {}
|
||||
|
||||
headers['User-Agent'] = config.user_agent
|
||||
|
||||
# Try 5 times
|
||||
|
@ -112,6 +93,7 @@ async def request(url, *, headers=None, payload=None, method='GET', attr='json')
|
|||
except:
|
||||
continue
|
||||
|
||||
|
||||
async def update_records(key, winner, loser):
|
||||
# We're using the Harkness scale to rate
|
||||
# http://opnetchessclub.wikidot.com/harkness-rating-system
|
||||
|
|
|
@ -32,6 +32,7 @@ youtube_dl.utils.bug_reports_message = lambda: ''
|
|||
|
||||
'''
|
||||
|
||||
|
||||
class Downloader:
|
||||
def __init__(self, download_folder=None):
|
||||
self.thread_pool = ThreadPoolExecutor(max_workers=2)
|
||||
|
@ -48,7 +49,6 @@ class Downloader:
|
|||
otmpl = self.safe_ytdl.params['outtmpl']
|
||||
self.safe_ytdl.params['outtmpl'] = os.path.join(download_folder, otmpl)
|
||||
|
||||
|
||||
@property
|
||||
def ytdl(self):
|
||||
return self.safe_ytdl
|
||||
|
@ -61,7 +61,8 @@ class Downloader:
|
|||
"""
|
||||
if callable(on_error):
|
||||
try:
|
||||
return await loop.run_in_executor(self.thread_pool, functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs))
|
||||
return await loop.run_in_executor(self.thread_pool,
|
||||
functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs))
|
||||
|
||||
except Exception as e:
|
||||
|
||||
|
@ -79,7 +80,9 @@ class Downloader:
|
|||
if retry_on_error:
|
||||
return await self.safe_extract_info(loop, *args, **kwargs)
|
||||
else:
|
||||
return await loop.run_in_executor(self.thread_pool, functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs))
|
||||
return await loop.run_in_executor(self.thread_pool,
|
||||
functools.partial(self.unsafe_ytdl.extract_info, *args, **kwargs))
|
||||
|
||||
async def safe_extract_info(self, loop, *args, **kwargs):
|
||||
return await loop.run_in_executor(self.thread_pool, functools.partial(self.safe_ytdl.extract_info, *args, **kwargs))
|
||||
return await loop.run_in_executor(self.thread_pool,
|
||||
functools.partial(self.safe_ytdl.extract_info, *args, **kwargs))
|
||||
|
|
|
@ -3,11 +3,13 @@ import json
|
|||
import os
|
||||
import traceback
|
||||
import time
|
||||
import discord
|
||||
import aiohttp
|
||||
|
||||
from discord import Embed
|
||||
from hashlib import md5
|
||||
from .exceptions import ExtractionError
|
||||
|
||||
|
||||
async def get_header(session, url, headerfield=None, *, timeout=5):
|
||||
with aiohttp.Timeout(timeout):
|
||||
async with session.head(url) as response:
|
||||
|
@ -16,6 +18,7 @@ async def get_header(session, url, headerfield=None, *, timeout=5):
|
|||
else:
|
||||
return response.headers
|
||||
|
||||
|
||||
def md5sum(filename, limit=0):
|
||||
fhash = md5()
|
||||
with open(filename, "rb") as f:
|
||||
|
@ -23,6 +26,7 @@ def md5sum(filename, limit=0):
|
|||
fhash.update(chunk)
|
||||
return fhash.hexdigest()[-limit:]
|
||||
|
||||
|
||||
class BasePlaylistEntry:
|
||||
def __init__(self):
|
||||
self.filename = None
|
||||
|
@ -48,8 +52,8 @@ class BasePlaylistEntry:
|
|||
|
||||
def get_ready_future(self):
|
||||
"""
|
||||
Returns a future that will fire when the song is ready to be played. The future will either fire with the result (being the entry) or an exception
|
||||
as to why the song download failed.
|
||||
Returns a future that will fire when the song is ready to be played. The future will either fire with the
|
||||
result (being the entry) or an exception as to why the song download failed.
|
||||
"""
|
||||
future = asyncio.Future()
|
||||
if self.is_downloaded:
|
||||
|
@ -159,7 +163,7 @@ class URLPlaylistEntry(BasePlaylistEntry):
|
|||
'type': self.meta[i].__class__.__name__,
|
||||
'id': self.meta[i].id,
|
||||
'name': self.meta[i].name
|
||||
} for i in self.meta
|
||||
} for i in self.meta
|
||||
}
|
||||
# Actually I think I can just getattr instead, getattr(discord, type)
|
||||
}
|
||||
|
@ -271,16 +275,17 @@ class URLPlaylistEntry(BasePlaylistEntry):
|
|||
else:
|
||||
# Move the temporary file to it's final location.
|
||||
os.rename(unhashed_fname, self.filename)
|
||||
|
||||
def to_embed(self):
|
||||
"""Returns an embed that can be used to display information about this particular song"""
|
||||
# Create the embed object we'll use
|
||||
embed = discord.Embed()
|
||||
embed = Embed()
|
||||
# Fill in the simple things
|
||||
embed.add_field(name='Title', value=self.title, inline=False)
|
||||
embed.add_field(name='Requester', value=self.requester.display_name, inline=False)
|
||||
# Get the current length of the song and display this
|
||||
length = divmod(round(self.length, 0), 60)
|
||||
fmt = "{0[0]}m {0[1]}s".format(length)
|
||||
embed.add_field(name='Duration', value=fmt,inline=False)
|
||||
embed.add_field(name='Duration', value=fmt, inline=False)
|
||||
# And return the embed we created
|
||||
return embed
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import shutil
|
||||
import textwrap
|
||||
|
||||
|
||||
# Base class for exceptions
|
||||
class MusicbotException(Exception):
|
||||
def __init__(self, message, *, expire_in=0):
|
||||
|
@ -15,14 +16,17 @@ class MusicbotException(Exception):
|
|||
def message_no_format(self):
|
||||
return self._message
|
||||
|
||||
|
||||
# Something went wrong during the processing of a command
|
||||
class CommandError(MusicbotException):
|
||||
pass
|
||||
|
||||
|
||||
# Something went wrong during the processing of a song/ytdl stuff
|
||||
class ExtractionError(MusicbotException):
|
||||
pass
|
||||
|
||||
|
||||
# The no processing entry type failed and an entry was a playlist/vice versa
|
||||
class WrongEntryTypeError(ExtractionError):
|
||||
def __init__(self, message, is_playlist, use_url):
|
||||
|
@ -30,12 +34,14 @@ class WrongEntryTypeError(ExtractionError):
|
|||
self.is_playlist = is_playlist
|
||||
self.use_url = use_url
|
||||
|
||||
|
||||
# The user doesn't have permission to use a command
|
||||
class PermissionsError(CommandError):
|
||||
@property
|
||||
def message(self):
|
||||
return "You don't have permission to use that command.\nReason: " + self._message
|
||||
|
||||
|
||||
# Error with pretty formatting for hand-holding users through various errors
|
||||
class HelpfulError(MusicbotException):
|
||||
def __init__(self, issue, solution, *, preface="An error has occured:\n", expire_in=0):
|
||||
|
@ -48,14 +54,14 @@ class HelpfulError(MusicbotException):
|
|||
def message(self):
|
||||
return ("\n{}\n{}\n{}\n").format(
|
||||
self.preface,
|
||||
self._pretty_wrap(self.issue, " Problem: "),
|
||||
self._pretty_wrap(self.issue, " Problem: "),
|
||||
self._pretty_wrap(self.solution, " Solution: "))
|
||||
|
||||
@property
|
||||
def message_no_format(self):
|
||||
return "\n{}\n{}\n{}\n".format(
|
||||
self.preface,
|
||||
self._pretty_wrap(self.issue, " Problem: ", width=None),
|
||||
self._pretty_wrap(self.issue, " Problem: ", width=None),
|
||||
self._pretty_wrap(self.solution, " Solution: ", width=None))
|
||||
|
||||
@staticmethod
|
||||
|
@ -72,17 +78,21 @@ class HelpfulError(MusicbotException):
|
|||
|
||||
return ''.join([l1, *lx])
|
||||
|
||||
|
||||
class HelpfulWarning(HelpfulError):
|
||||
pass
|
||||
|
||||
|
||||
# Base class for control signals
|
||||
class Signal(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# signal to restart the bot
|
||||
class RestartSignal(Signal):
|
||||
pass
|
||||
|
||||
|
||||
# signal to end the bot "gracefully"
|
||||
class TerminateSignal(Signal):
|
||||
pass
|
||||
|
|
|
@ -4,7 +4,7 @@ from collections import deque
|
|||
from itertools import islice
|
||||
from random import shuffle
|
||||
|
||||
from .entry import URLPlaylistEntry
|
||||
from .entry import URLPlaylistEntry, get_header
|
||||
from .exceptions import ExtractionError, WrongEntryTypeError
|
||||
from .event_emitter import EventEmitter
|
||||
|
||||
|
|
Loading…
Reference in a new issue