async def misc_commands(self, ctx): """Sends a link to the list of available *dumb commands*. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) embed = quickembed.info( desc= 'FJBot Command:\nhttps://idleuser.com/projects/fjbot/command-list', user=DiscordUser(ctx.author), ) await ctx.send(embed=embed)
async def mock_member(self, ctx, member: discord.Member = None): """Spongebob mocking memes a Discord users last message. .. note:: The user being mocked must have a message within the last 50 messages in the channel that is not a command. Otherwise, nothing will happen. You cannot mock non-Discord user or a bot. :param ctx: The invocation context. :param member: The Discord user to mock. """ user = DiscordUser(ctx.author) if member and not member.bot: async for m in ctx.channel.history(limit=50): if m.author == member and not m.content.startswith('!'): mock_msg_list = [] alpha_cnt = 0 for letter in m.content: if not letter.isalpha(): mock_msg_list.append(letter) continue alpha_cnt += 1 if alpha_cnt % 2: mock_msg_list.append(letter.upper()) else: mock_msg_list.append(letter.lower()) mock_msg = ''.join(mock_msg_list) embed = quickembed.info('```"{}"\n - {}```'.format( mock_msg, member), user=user) await ctx.send(embed=embed) break
async def tickle_member(self, ctx, member: discord.Member = None, *, reason='no reason provided'): """Tickle another Discord user. :param ctx: The invocation context. :param member: The Discord user to tickle. :param reason: The reason for the tickle. """ user = DiscordUser(ctx.author) if not member: embed = quickembed.info( '{} tried to tickle someone, but everyone is ran away.'.format( user.mention), user=user, ) elif member.bot: embed = quickembed.info( "{} spread {}'s cheeks and tickled the inside for trying to touch a bot" .format(member.mention, user.mention), user=user, ) elif member == ctx.author: embed = quickembed.info('{} tickled themself. Pathetic..'.format( user.mention), user=user) else: embed = quickembed.info( '{} tickled {}\nReason: {}'.format(user.mention, member.mention, reason), user=user, ) await ctx.send(embed=embed)
async def delete_spam_messages(self, ctx): """Deletes duplicate messages in the channel. .. Note:: Messages are checked per author. The original message will remain. :param ctx: The invocation context. """ msgs = [] spam = [] async for msg in ctx.channel.history(limit=50): c = str(msg.author) + msg.content if c in msgs: spam.append(msg) else: msgs.append(c) spam.append(ctx.message) await ctx.channel.delete_messages(spam) if len(spam) > 1: embed = quickembed.info( '```Deleted {} spam messages```'.format(len(spam)), DiscordUser(ctx.author), ) self.bot.log(embed=embed)
async def hug_member(self, ctx, member: discord.Member = None, *, reason='no reason provided'): """Hug another Discord user. :param ctx: The invocation context. :param member: The Discord user to hug. :param reason: The reason for the hug. """ user = DiscordUser(ctx.author) if not member: embed = quickembed.info( '{} tried to hug someone, but no one was there.'.format( user.mention), user=user, ) elif member.bot: embed = quickembed.info( "{} tried to hug a {}, but is rejected. Even bots doesn't like you." .format(user.mention, member.mention), user=user, ) elif member == ctx.author: embed = quickembed.info('{} hugged themself. Pathetic..'.format( user.mention), user=user) else: embed = quickembed.info( '{} hugged {}\nReason: {}'.format(user.mention, member.mention, reason), user=user, ) await ctx.send(embed=embed)
async def unmute_member(self, ctx, member: discord.Member): """Unmutes a member by removing their `Muted` role. .. Note:: Requires `Manage Roles` privilege. .. Note:: A `Muted` role must exist with the proper permissions. It's a simple role that can only read the channels and not send messages. :param ctx: The invocation context. :param member: """ user = DiscordUser(ctx.author) role = discord.utils.find(lambda r: r.name == 'Muted', ctx.guild.roles) if not role: embed = quickembed.error(desc='`Muted` role does not exist', user=user) elif role in member.roles: await member.remove_roles(role) embed = quickembed.success(desc='Unmuted {}'.format(member), user=user) else: embed = quickembed.error( desc='{} is already unmuted'.format(member), user=user) await ctx.send(embed=embed)
async def open_matches(self, ctx): """Lists the available `Match`es to bet on. .. Note: If the number of available `Match`es exceeds 5, they will be displayed with their `short view`. If it does not exceed 5, their full details will be displayed as individual messages. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) rows = user.search_match_by_open_bets() if len(rows) > 5: embed = quickembed.info( desc='Short View - Use `!match [id]` for full view') embed.set_author(name='Open Bet Matches') for row in rows: match = Match(row.id) embed.add_field( name='[Match {}]'.format(match.id), value='{}'.format(match.info_text_short()), inline=True, ) await ctx.send(embed=embed) elif len(rows) > 0: for row in rows: await ctx.send(embed=Match(row.id).info_embed()) else: await ctx.send(embed=quickembed.error( desc='No open bet matches available', user=user))
async def update_guild_prefix(self, ctx, prefix): """Updates the command prefix for the Discord server. .. Note:: Requires `administrator` privilege. :param ctx: The invocation context. :param prefix: The command prefix to update to. """ user = DiscordUser(ctx.author) if len(prefix) > 3: embed = quickembed.error( desc='Prefix can not be longer than 3 characters', user=user) else: user.update_guild_info(ctx.guild, prefix) stored_prefix = user.guild_info(ctx.guild.id)['prefix'] if prefix == stored_prefix: embed = quickembed.success( desc='Prefix updated to **{}**'.format(stored_prefix), user=user, ) else: embed = quickembed.error(desc='Failed to update prefix', user=user) await ctx.send(embed=embed)
async def member_roles(self, ctx): """Displays the roles the requesting user currently has in the server. :param ctx: The invocation context. """ roles = '{}'.format([role.name for role in ctx.author.roles]) embed = quickembed.info(desc='Roles: {}'.format(roles), user=DiscordUser(ctx.author)) await ctx.send(embed=embed)
async def fjbucks_balance(self, ctx): """ .. Important:: Work in progress. :param ctx: The invocation context. """ await ctx.send(embed=DiscordUser(ctx.author).fjbucks_wallet_embed())
async def flip_coin(self, ctx): """Performs a basic coin flip and displays the result. :param ctx: The invocation context. """ result = 'Heads' if random.getrandbits(1) else 'Tails' embed = quickembed.info(desc='Coin flip', user=DiscordUser(ctx.author)) embed.add_field(name=result, value='\u200b', inline=False) await ctx.send(embed=embed)
async def roll_dice(self, ctx): """Performs a basic dice roll and returns the result. :param ctx: The invocation context. """ result = '[{}] [{}]'.format(random.randint(1, 6), random.randint(1, 6)) embed = quickembed.info(desc='Dice roll', user=DiscordUser(ctx.author)) embed.add_field(name=result, value='\u200b', inline=False) await ctx.send(embed=embed)
async def uptime(self, ctx): """Display the amount of time the bot has been alive. :param ctx: The invocation context. """ embed = quickembed.info( desc='Uptime: {}'.format(datetime.now() - self.bot.start_dt), user=DiscordUser(ctx.author), ) await ctx.send(embed=embed)
async def pause_audio(self, ctx): """Pauses the audio player. :param ctx: The invocation context. """ if ctx.voice_client and ctx.voice_client.is_playing(): ctx.voice_client.pause() await ctx.send( embed=quickembed.info(desc=':mute: Paused the party :mute:', user=DiscordUser(ctx.author)))
async def stop_audio(self, ctx): """Stops the audio and leaves the voice channel. :param ctx: The invocation context. """ if ctx.voice_client: await ctx.voice_client.disconnect() await ctx.send( embed=quickembed.info(desc=':mute: Stopped the party :mute:', user=DiscordUser(ctx.author)))
async def resume_audio(self, ctx): """Resumes the audio player. :param ctx: The invocation context. """ if ctx.voice_client and ctx.voice_client.is_paused(): ctx.voice_client.resume() await ctx.send(embed=quickembed.info( desc=':musical_note: Resumed the party :musical_note:', user=DiscordUser(ctx.author), ))
async def invite(self, ctx): """Sends the Discord server invite link defined in :mod:`config`. :param ctx: The invocation context. """ embed = quickembed.info( desc='Invite Link:\n{}\n\nInvite Bot:\n{}'.format( config.base['invite']['guild'], config.base['invite']['bot']), user=DiscordUser(ctx.author), ) await ctx.send(embed=embed)
async def joined(self, ctx, member: discord.Member = None): """Displays the date the user joined the Discord server. :param ctx: The invocation context. :param member: The Discord user to display. """ member = member if member else ctx.author embed = quickembed.info( desc='{0.name} joined on `{0.joined_at}`'.format(member), user=DiscordUser(ctx.author), ) await ctx.send(embed=embed)
async def recent_match_info(self, ctx): """Displays details for the last completed `Match`. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) rows = user.search_match_by_recent_completed() if rows: embed = Match(rows[0].id).info_embed() else: embed = quickembed.error(desc='No match found', user=user) await ctx.send(embed=embed)
async def user_join_royalrumble(self, ctx): """TODO: Enters the user into the current Royal Rumble event by providing them an entry number. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) response = user.join_royalrumble() if response['success']: embed = quickembed.success(desc='Entry Number: `{}`'.format( response['message']), user=user) else: embed = quickembed.error(desc=response['message'], user=user) await ctx.send(embed=embed)
async def superstar_birthdays(self, ctx): """Display a list of upcoming `Superstar` birthdays. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) bdays = user.superstar_birthday_upcoming() embed = quickembed.info(desc='Upcoming Birthdays', user=user) embed.add_field( name='\u200b', value='{}'.format('\n'.join( ['[{}] - {}'.format(b['dob'], b['name']) for b in bdays])), ) await ctx.send(embed=embed)
async def rate_match(self, ctx, *args): """Adds a 0-5 star rating to a `Match`. .. Note: If no `match_id` is provided, the rating will be added to the most recently closed `Match`. :param ctx: The invocation context. :param args: Must be either `[rating]` or `[match_id] [rating]`. Rating must be between 0-5. :return: """ user = DiscordUser(ctx.author) try: if len(args) == 1: match_id = None rating = float(args[0]) else: match_id = int(args[0]) rating = float(args[1]) except Exception: msg = ('Invalid `!rate` command\n' '`!rate [rating]` (rates last match)\n' '`!rate [match_id] [rating]`') embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed) return if not match_id: rows = user.search_match_by_recent_completed() if not rows: msg = 'No current match set to rate' embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed) return match_id = rows[0].id response = user.rate_match(match_id, rating) if response['success']: match = Match(match_id) stars = '' for i in range(1, 6): if rating >= i: stars += '★' else: stars += '☆' msg = 'Rated `Match {}` {} ({})\n{}'.format( match_id, stars, rating, match.info_text_short()) embed = quickembed.success(desc=msg, user=user) else: msg = response['message'] embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed)
async def check_registered_users(self): await self.bot.wait_until_ready() guild = self.bot.get_guild(config.base['guild_id']) role = guild.get_role(753640365612990546) members = guild.members for member in guild.members: user = DiscordUser(member) is_registered = user.is_registered() has_role = role in member.roles if is_registered and not has_role: await member.add_roles(role) logger.info('Added @registered to: {}'.format(user.name)) elif not is_registered and has_role: await member.remove_roles(role) logger.info('Removed @registered from: {}'.format(user.name))
async def user_reset_password_link(self, ctx): """Sends a reset password link for the website to the user through DM. .. note:: This bypasses the login credentials by using a temporary password. The temporary password is only valid for resetting the account's password. It expires once the password has changed or 5 minutes has passed. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) link = user.request_reset_password_link() msg = '<{}>\n(link expires in 5 minutes)'.format(link) await ctx.author.send(embed=quickembed.general(desc=msg, user=user)) embed = quickembed.success(user=user, desc='Link DMed') await ctx.send(embed=embed)
async def upcoming_events(self, ctx): """Displays a list of upcoming PPV events in order. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) ppvs = user.future_events(ppv_check=1) embed = quickembed.info(desc='Upcoming Events (PT)', user=user) embed.add_field( name='\u200b', value='\n'.join([ '{} - **{}**'.format(e['date_time'], e['name']) for e in ppvs ]), ) await ctx.send(embed=embed)
async def donate_bucks(self, ctx, amount: int, member: discord.Member): """Sends another user FJBucks from their own wallet. .. Important:: Work in progress. :param ctx: The invocation context. :param amount: The amount of FJBucks to send :param member: The Discord member to send to. """ user = DiscordUser(ctx.author) recipient = DiscordUser(member) if not recipient.is_registered(): embed = quickembed.error(desc='{} is not registered'.format( recipient.name), user=user) else: recipient.fjbucks_transaction(amount, 'owner authorized') embed = quickembed.success( desc='Donated **{} FJBucks** to {}'.format( amount, recipient.name), user=user, ) await ctx.send(embed=embed)
async def add_discord_command(self, ctx, command, *, response): """Inserts a quick chatroom command. :param ctx: The invocation context. :param command: The command name to add. :param response: The response for the command. """ user = DiscordUser(ctx.author) command = '!{}'.format(command.strip('!')) res = user.add_chatroom_command(command, response) if res['success']: embed = quickembed.success( desc='Command `{}` updated'.format(command), user=user) else: embed = quickembed.error(desc='Failed', user=user) await ctx.send(embed=embed)
async def user_login_link(self, ctx): """Sends a quick login link for the website to the user through DM. .. note:: This bypasses the website login by using a temporary token. The token expires once the link is used or 5 minutes has passed. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) link = user.request_login_link() msg = 'Quick login link for you! (link expires in 5 minutes)\n<{}>'.format( link) await ctx.author.send(embed=quickembed.general(desc=msg, user=user)) embed = quickembed.success(user=user, desc='Login link DMed') await ctx.send(embed=embed)
async def send_discord_id(self, ctx): """Sends the user's Discord id through DM. This is useful for users that join through the website and have not linked their Discord accounts to their profile. After logging in to the website, their profile has a Discord ID field that they can fill. Once the value is set, the account is linked. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) msg = ('Your discord_id is: `{}`\n' 'Link it to your http://idleuser.com/projects/matches profile.'. format(user.discord.id)) embed = quickembed.general(desc=msg, user=user) await ctx.author.send(embed=embed) await ctx.send( embed=quickembed.general(desc='Information DMed', user=user))
async def change_volume(self, ctx, volume: int): """Updates the current audio player's volume. .. Note:: The volume received is divided by 100 because the player's volume value must be a float between 0 and 1. Think of the input as a percentage. :param ctx: The invocation context. :param volume: The percentage of the audio. Should be 0-100. """ user = DiscordUser(ctx.author) if ctx.voice_client is None: await ctx.send(embed=quickembed.error( desc='Not connected to a voice channel', user=user)) ctx.voice_client.source.volume = volume / 100 await ctx.send(embed=quickembed.info( desc='Changed volume to {}%'.format(volume), user=user))