async def awoo_whitelist(bot, context): """(De)whitelists the given user.""" user = context.arguments[0] whitelist = data.get(bot, __name__, 'whitelist', guild_id=context.guild.id, default=[]) # (De)whitelist user if user: if user.id in whitelist: action = 'removed from' data.list_data_remove(bot, __name__, 'whitelist', value=user.id, guild_id=context.guild.id) else: action = 'added to' data.list_data_append(bot, __name__, 'whitelist', user.id, guild_id=context.guild.id) return Response(content="User {} the whitelist.".format(action)) # Show whitelisted users else: if not whitelist: raise CBException("There are no whitelisted users.") users = [(data.get_member(bot, it, attribute='mention') or 'Unknown ({})'.format(it)) for it in whitelist] return Response(embed=discord.Embed(title="Whitelisted users", description=', '.join(users)))
async def respond(self, message, context, response, replacement_message=None): """Takes a response and sends a basic message. Returns message_reference.""" message_reference = None send_arguments = response.get_send_kwargs(replacement_message) try: # Edit the replacement_message as the response if replacement_message: try: await replacement_message.edit(**send_arguments) message_reference = replacement_message except discord.NotFound: # Message deleted response = Response() message_reference = None # Send a new message as the response elif (not response.is_empty() and not (self.selfbot and response.message_type is MessageTypes.REPLACE)): destination = response.destination or message.channel message_reference = await destination.send(**send_arguments) response.message = message_reference plugins.broadcast_event(self, 'bot_on_response', response, context) except Exception as e: message_reference = await self.handle_error( e, message, context, response, edit=replacement_message, command_editable=True) return message_reference
async def character_create(bot, context): """Creates a new character entry.""" # Check if an entry is currently being created/edited tracker = data.get(bot, __name__, 'tracker', user_id=context.author.id, volatile=True) if tracker: return Response( content=( "You are currently already creating or editing a character entry. " "Would you like to cancel your current session?"), message_type=MessageTypes.INTERACTIVE, extra_function=_cancel_menu, extra={'buttons': ['🇾', '🇳']}) # 10 character limit cursor = data.db_select( bot, from_arg='characters', where_arg='owner_id=%s', input_args=[context.author.id]) characters = cursor.fetchall() if cursor else [] if len(characters) >= 10: raise CBException("Cannot create more than 10 characters.") # Use the provided character file if context.message.attachments: content = await _process_data( bot, context.author, context.message.attachments[0].url, propagate_error=True) return Response(content=content) # Use the online entry creator else: await _create_session(bot, context.author) if not context.direct: await context.message.add_reaction('📨')
async def get_response(bot, context): response = Response() if context.author.voice: voice_channel = context.author.voice.channel voice_client = await utilities.join_and_ready(bot, voice_channel) options = {'format': 'bestaudio/best', 'noplaylist': True} downloader = YoutubeDL(options) url = context.arguments[0] try: file_location = data.get_from_cache(bot, None, url=url) if not file_location: logger.info("Not found in cache. Downloading...") info = await utilities.future(downloader.extract_info, url, download=False) download_url = info['formats'][0]['url'] file_location = await data.add_to_cache(bot, download_url, name=url) ffmpeg_options = '-protocol_whitelist "file,http,https,tcp,tls"' voice_client.play(discord.FFmpegPCMAudio(file_location, before_options=ffmpeg_options)) except BotException as e: raise e # Pass up except Exception as e: raise CBException("Something bad happened.", e=e) response.content = "Playing your stuff." else: raise CBException("You're not in a voice channel.") return response
async def role_list(bot, context): """Lists the available roles for self-assignment.""" if context.arguments[0]: # List members that have this role role = context.arguments[0] if role.is_default(): raise CBException("Cannot list members with the @everyone role.") if not role.members: raise CBException("No members have the role {}.".format(role.mention)) elif len(role.members) > 80: name_file = discord.File( utilities.get_text_as_file('\n'.join(str(it) for it in role.members)), filename='members.txt') embed = discord.Embed( description='{} members have this role.'.format(len(role.members))) return Response(file=name_file, embed=embed) else: plural = len(role.members) > 1 return Response(embed=discord.Embed( title='{} member{} {} this role:'.format( len(role.members), 's' if plural else '', 'have' if plural else 'has'), description=', '.join(it.mention for it in role.members))) else: # List self-assignable roles available_roles = _check_roles(bot, context.guild) if not available_roles: raise CBException("There are no self-assignable roles available.") embed = discord.Embed( title='Self-assignable roles:', description='\n'.join(it.mention for it in available_roles)) embed.set_footer(text='To join a role, use {}role join'.format( utilities.get_invoker(bot, guild=context.guild))) return Response(embed=embed)
async def get_response(bot, context): response = Response() if context.author.voice: voice_channel = context.author.voice.channel voice_client = await utilities.join_and_ready(bot, voice_channel) options = {'format': 'bestaudio/best', 'noplaylist': True} downloader = YoutubeDL(options) url = context.arguments[0] try: file_location = data.get_from_cache(bot, None, url=url) if not file_location: logger.info("Not found in cache. Downloading...") info = await utilities.future(downloader.extract_info, url, download=False) download_url = info['formats'][0]['url'] file_location = await data.add_to_cache(bot, download_url, name=url) ffmpeg_options = '-protocol_whitelist "file,http,https,tcp,tls"' voice_client.play( discord.FFmpegPCMAudio(file_location, before_options=ffmpeg_options)) except BotException as e: raise e # Pass up except Exception as e: raise CBException("Something bad happened.", e=e) response.content = "Playing your stuff." else: raise CBException("You're not in a voice channel.") return response
async def _get_response(self, context): """Takes a context and builds a response.""" response = await commands.execute(self, context) if response is None: response = Response() elif self.selfbot and response.content: response.content = '\u200b' + response.content return response
async def role_verification(bot, context): """Sets or clears a verification role to allow self-assignment.""" role = context.arguments[0] if role: data.add_custom_role(bot, __name__, 'verified', role) return Response(embed=discord.Embed( description='Only users with the {} role can self-assign roles.'.format(role.mention))) else: data.remove_custom_role(bot, __name__, 'verified', context.guild) return Response(embed=discord.Embed(description='Anybody can now self-assign roles.'))
async def take_attendance(bot, context): """Takes all users in voice channel and logs it.""" response = Response() # VARS attendance_list = [] day_of_week = None # 0 = Monday, 6 = Sunday index_of_nw_attendance = None # checks to see if user is in voice channel if not context.author.voice: raise CBException('You must be in a voice channel to use this feature.') voice_channel = context.author.voice.channel # get all members within voice channel for member in voice_channel.members: attendance_list.append(member) if len(attendance_list) == 1: raise CBException('Are you really node warring with yourself? Loser.') # get day day_of_week = datetime.datetime.today().weekday() if day_of_week == 5: raise CBException('Since when did Influence siege? lmfao pvx guild btw') # opens spreadsheet + nw attendance sh = await utilities.future(gc.open, SPREADSHEET_NAME) worksheet = await utilities.future(sh.worksheets) # get index of nw attendance for i, sheet in enumerate(worksheet): if NW_ATTENDANCE_NAME in str(sheet): index_of_nw_attendance = i nw_attendance = await utilities.future(sh.get_worksheet, index_of_nw_attendance) # error handling if index_of_nw_attendance == None: response.content = 'Something went wrong when initializing sheets (check nw attendance name).' return response for index in range(len(attendance_list)): if day_of_week == 6: # if sunday await utilities.future(nw_attendance.update_cell, 3+index, NW_SUNDAY, str(attendance_list[index])) else: await utilities.future(nw_attendance.update_cell, 3+index, NW_MONDAY+day_of_week, str(attendance_list[index])) response.content = 'Attendance successfully taken.' return response
async def awoo_leaderboard(bot, context): """Displays the top 10 violators.""" cursor = data.db_select(bot, from_arg='awoo', additional='ORDER BY debt DESC', limit=10) entries = cursor.fetchall() if cursor else [] if not entries: raise CBException("Nobody has made any awoo violations yet!") stats = [[], []] # debt/violations, user for index, entry in enumerate(entries): stats[0].append('`{0}.` ${1.debt} | {1.violations}'.format( index + 1, entry)) user = data.get_member(bot, entry.user_id, safe=True, attribute='mention') user = user or 'Unknown ({})'.format(entry.user_id) stats[1].append('`\u200b`{}'.format(user)) embed = discord.Embed(title=':scales: Awoo violation leaderboard') embed.add_field(name='Debt | Violations', value='\n'.join(stats[0])) embed.add_field(name='User', value='\n'.join(stats[1])) return Response(embed=embed)
async def role_create(bot, context): """Creates the given role.""" role_name = context.arguments[0] guild_role_names = list(it.name.lower() for it in context.guild.roles) if role_name.lower() in guild_role_names: raise CBException("A similarly named role already exists.") color = context.options.get('color', discord.Color.default()) hoisted, mentionable = 'hoisted' in context.options, 'mentionable' in context.options try: new_role = await context.guild.create_role( name=role_name, color=color, hoist=hoisted, mentionable=mentionable, reason='Created self-assigned role') except discord.Forbidden: raise CBException("The bot is missing the `Manage Roles` permission.") data.list_data_append( bot, __name__, 'roles', new_role.id, guild_id=context.guild.id, duplicates=False) embed = discord.Embed( title='Created a new self-assignable role:', description='{}\n{}\n{}'.format( new_role.mention, 'Hoisted' if hoisted else '', 'Mentionable' if mentionable else '').strip(), color=color if 'color' in context.options else discord.Embed.Empty) return Response(embed=embed)
async def verification_karma(bot, context): """Checks if the given user has karma in the r/furry subreddit.""" verified_role = _get_verified_role(bot, context.guild) karma = await _check_reddit_karma(bot, context.arguments[0]) threshold = configurations.get(bot, __name__, 'karma_threshold') # Replace karma amount with limits if it is past that limits = [ configurations.get(bot, __name__, 'submission_karma_limit'), configurations.get(bot, __name__, 'comment_karma_limit') ] zipped = zip(karma, limits) karma_strings = [(str(it) if it <= ts else (str(ts) + '+')) for it, ts in zipped] if sum(karma) >= threshold: response = ':white_check_mark: {} submission karma, {} comment karma' qualifies = 'qualifies' color = discord.Color(0x77b255) else: response = ':x: {} submission karma, {} comment karma' qualifies = 'needs at least {} combined karma'.format(threshold) color = discord.Color(0xdd2e44) description = '{0}\n[u/{1}](https://www.reddit.com/user/{1}) {2} for {3}'.format( response.format(*karma_strings), context.arguments[0], qualifies, verified_role.mention) return Response(embed=discord.Embed(description=description, color=color))
async def commission_configure(bot, context): """Configures the channel and cooldown for the commission channel rules.""" rules = data.get(bot, __name__, 'rules', guild_id=context.guild.id, default={}) default_cooldown = configurations.get(bot, __name__, 'default_cooldown') replace_channel = context.options.get('channel', rules.get('channel')) replace_cooldown = context.options.get( 'cooldown', rules.get('cooldown', default_cooldown)) if not replace_channel: raise CBException("No commission channel configured.") # Reset advertisement data rules = {'channel': replace_channel, 'cooldown': replace_cooldown} data.add(bot, __name__, 'rules', rules, guild_id=context.guild.id) data.remove(bot, __name__, 'advertisements', guild_id=context.guild.id, volatile=True, safe=True) await _get_advertisement_data(bot, context.guild) description = 'Channel: {0.mention}\nCooldown: {1}'.format( data.get_channel(bot, replace_channel), utilities.get_time_string(replace_cooldown, text=True, full=True)) embed = discord.Embed(title='Commission channel configuration:', description=description) return Response(embed=embed)
async def tagremote_update(bot, context): """Renames the webhook with an updated tag list file.""" # Check for an existing session session_data = data.get(bot, __name__, 'data', guild_id=context.guild.id) if not session_data: raise CBException("No session available.") channel = data.get_channel(bot, session_data['channel']) if not channel: await _delete_session(bot, context.guild) raise CBException("Failed to get the channel.") voice_channel = data.get_channel(bot, session_data['voice_channel']) if not voice_channel: await _delete_session(bot, context.guild) raise CBException("Failed to get the voice channel.") webhooks = await channel.webhooks() if not webhooks: await _delete_session(bot, context.guild) raise CBException("No webhooks available.") for webhook in webhooks: if webhook.id == session_data['webhook']: break else: await _delete_session(bot, context.guild) raise CBException("Webhook not found.") tag_dictionary = _get_tag_dictionary(bot, context.guild) session_code = await _upload_session_data(bot, channel, voice_channel, webhook, tag_dictionary) updated_code = session_code.split(':')[1] await webhook.edit(name='Tag Remote [{}]'.format(updated_code)) return Response( content="Tag data refreshed. Update the remote on your phone via the options menu.")
async def run_query(bot, context): results = context.options['results'] text_result = 'text' in context.options query_url, result, warning = await get_query_result( bot, context.guild, context.arguments[0], text_result=text_result, result_lines=results) if configurations.get(bot, __name__, 'ads'): location = context.channel if context.direct else context.guild advertisement = get_advertisement(bot, location) else: advertisement = None embed = discord.Embed( description=advertisement if advertisement else discord.Embed.Empty, colour=discord.Colour(0xdd1100)) embed.set_author(name='Query', url=query_url, icon_url='https://i.imgur.com/mFfV1zk.png') if text_result: for name, value in result: embed.add_field(name=name, value=value, inline=False) else: embed.set_image(url=result) if warning: embed.set_footer(text=warning, icon_url='https://i.imgur.com/CGl7njZ.png') return Response(embed=embed)
async def get_roll(bot, context): """Gets a random roll in the D&D syntax style.""" rolls, sides, bonus = context.arguments[0] max_characters = len(str(sides)) results = [random.randint(1, sides) for it in range(rolls)] text_results = [ '`{: <{}}\u200b`'.format(it, max_characters) for it in results ] split_results = [ text_results[it:it + 10] for it in range(0, len(text_results), 10) ] result_text = '\n'.join(', '.join(it) for it in split_results) embed = discord.Embed(title=':game_die: Dice roll', description=result_text) total = sum(results) if rolls > 1: embed.add_field(name='Sum', value=str(total)) embed.add_field(name='Mean', value='{:.2f}'.format(total / len(results))) if bonus: embed.add_field(name='Final', value=str(total + bonus)) return Response(embed=embed)
async def role_joinleave(bot, context): """Adds/removes the given role(s) to/from the member.""" # Check for a verified role verified_role = data.get_custom_role(bot, __name__, 'verified', context.guild) if verified_role: if not data.has_custom_role(bot, __name__, 'verified', member=context.author): raise CBException("You must have the role {} in order to self-assign roles.".format( verified_role.mention)) joining = context.id == 'join' available_role_ids = data.get(bot, __name__, 'roles', guild_id=context.guild.id, default=[]) for role in context.arguments: if role.id not in available_role_ids: raise CBException("The role {} is not self-assignable.".format(role.mention)) try: action_function = context.author.add_roles if joining else context.author.remove_roles await action_function(*context.arguments, reason="Self-assignable role") except discord.Forbidden: if not context.guild.me.guild_permissions.manage_roles: raise CBException("The bot is missing the `Manage Roles` permission.") _check_roles(bot, context.guild) action = 'assign' if joining else 'remov' raise CBException("The role(s) could not be {}ed due to a hierarchy issue.".format(action)) embed = discord.Embed( title='You have {} the role{}:'.format( 'joined' if joining else 'left', '' if len(context.arguments) == 1 else 's'), description='\n'.join(it.mention for it in context.arguments)) return Response(embed=embed)
async def to_be_belled(bot, context): server = context.arguments[0] bell_minutes = context.arguments[1] response = Response() # check inputs if server not in SERVERS: response.content = '{} is not a valid server.'.format(server) return response if bell_minutes < 1 or bell_minutes > 60: response.content = 'The bell time must be between 1 and 60 minutes.' return response # passes checks, update BELL_SERVERS BELL_SERVERS[server] = ['YES', bell_minutes, round(time.time())]
async def character_remove(bot, context): """Removes a character entry.""" clean_name = context.arguments[0].clean_name data.db_delete( bot, 'characters', where_arg='clean_name=%s AND owner_id=%s', input_args=(clean_name, context.author.id)) return Response(content="Character deleted.")
async def character_browse(bot, context): """Browses a list of all characters.""" character_listing = data.db_select( bot, from_arg='characters', additional='ORDER BY clean_name ASC').fetchall() if not character_listing: raise CBException("There are no characters in the database.") page_index = 0 if context.arguments[0]: search = context.arguments[0] closest_index = 0 for index, character in enumerate(character_listing): if search <= character.clean_name: closest_index = index else: break page_index = int(closest_index / 10) # 10 entries per page embed = discord.Embed( title=':book: Character browser', description='{} total character{}'.format( len(character_listing), '' if len(character_listing) == 1 else 's')) state_data = [page_index, character_listing] return Response( embed=_build_browser_menu(bot, embed, *state_data), message_type=MessageTypes.INTERACTIVE, extra_function=_browser_menu, extra={'buttons': ['⬅', '➡'], 'userlock': False}, state_data=state_data)
async def translate(bot, context): """Translates the given text.""" source = context.options.get('from', 'auto') if 'to' in context.options: destination = context.options['to'] else: if context.direct: destination = 'en' else: destination = data.get( bot, __name__, 'default', guild_id=context.guild.id, default='en') try: result = await utilities.future( TRANSLATOR.translate, context.arguments[0], src=source, dest=destination) except ValueError as e: if 'source' in e.args[0]: issue, language = 'source', source else: issue, language = 'destination', destination raise CBException("Invalid {} language (`{}`).\n{}".format(issue, language, LANGUAGE_LINK)) except Exception as e: raise CBException("Failed to translate the text.", e) full_source = googletrans.constants.LANGUAGES[result.src.lower()].title() full_destination = googletrans.constants.LANGUAGES[result.dest.lower()].title() embed = discord.Embed( title=':arrows_counterclockwise: Google Translate', color=discord.Color(0x3b88c3)) embed.add_field(name=full_source, value=context.arguments[0], inline=False) embed.add_field(name=full_destination, value=result.text, inline=False) return Response(embed=embed)
async def custom_notify(bot, context): """This is only called with the notify command. This function is called with the same arguments as get_response. """ await utilities.notify_owners( bot, '{0.author} from {0.guild}: {0.arguments[0]}'.format(context)) return Response(content="Notified the owners with your message!")
async def commission_list(bot, context): """Lists the users that have advertised in the commission channel.""" advertisement_data = await _get_advertisement_data(bot, context.guild) return Response( embed=discord.Embed(title='List of advertisers:', description=', '.join( it.author.mention for it in advertisement_data.values())))
async def translate_languages(bot, context): """Gets a list of valid language codes.""" codes = ['{} [`{}`]'.format(v.title(), k) for k, v in googletrans.constants.LANGUAGES.items()] code_break = int(len(codes)/3) + 1 code_split = [codes[it:it + code_break] for it in range(0, len(codes), code_break)] embed = discord.Embed(title='Language list') for split in code_split: embed.add_field(name='\u200b', value='\n'.join(split)) return Response(embed=embed)
async def autolog_setchannel(bot, context): """Sets the channel where logs will be dumped.""" data.add(bot, __name__, 'log_channel', context.arguments[0].id, guild_id=context.guild.id) return Response("The logging channel is now set to {}".format( context.arguments[0].mention))
async def add_text(bot, context): text_type, new_text = context.arguments table_name = 'txyz_' + TYPE_NAMES[text_type] data.db_insert(bot, table_name, specifiers='value', input_args=new_text, safe=False) return Response(content='Added a {}.'.format(table_name[5:-1]))
async def translate_default(bot, context): """Sets the default translation language.""" language = context.arguments[0] if language: data.add(bot, __name__, 'default', language, guild_id=context.guild.id) else: data.remove(bot, __name__, 'default', guild_id=context.guild.id) return Response( content='Default language set to {}.'.format(language if language else 'English'))
async def remove_text(bot, context): text_type, entry_id = context.arguments table_name = 'txyz_' + TYPE_NAMES[text_type] data.db_delete(bot, table_name, where_arg='key=%s', input_args=[entry_id], safe=False) return Response( content='Removed {} entry {}.'.format(table_name[5:-1], entry_id))
async def verification_set(bot, context): """Sets the verification role.""" role = context.arguments[0] data.add(bot, __name__, 'verification_role', role.id, guild_id=context.guild.id) return Response(embed=discord.Embed( description='Verification role set to {}'.format(role.mention)))
async def awoo_reset(bot, context): """Removes the given user from the database.""" user = context.arguments[0] removed = data.db_delete(bot, 'awoo', where_arg='user_id=%s', input_args=[user.id]) if not removed: raise CBException("User not in violation database.") return Response(content="User removed from the database.")
async def list_text(bot, context): list_lines = [] for text_type in TYPE_NAMES: list_lines.append('\n\n' + text_type) cursor = data.db_select(bot, from_arg='txyz_' + text_type) for key, value in cursor.fetchall(): list_lines.append('\t{}: {}'.format(key, value)) text_file = utilities.get_text_as_file('\n'.join(list_lines)) discord_file = discord.File(text_file, 'txyz_list.txt') return Response(content='Table contents:', file=discord_file)
async def live_enable(bot, context): url_suffix = context.message.attachments[0].url.split('/', 4)[-1] channel_name = '_1{visible}{fullscreen}{theme}{weather}{audio}|{url_suffix}'.format( visible=0 if 'invisible' in context.options else 1, url_suffix=url_suffix, **context.options) txyz_guild = bot.get_guild(TXYZ_GUILD) await txyz_guild.voice_channels[3].edit(name=channel_name) return Response( content='Live page enabled with code: {}'.format(channel_name))
async def commission_whitelist(bot, context): """Whitelists the given user from the commission channel limits.""" if context.arguments[0]: # Toggle user added = data.list_data_toggle(bot, __name__, 'whitelist', context.arguments[0], guild_id=context.guild.id) return Response( '{}ed user {} the commission channel rules whitelist.'.format( *(('Add', 'to') if added else ('Remov', 'from')))) else: # List users users = data.get(bot, __name__, 'whitelist', guild_id=context.guild.id) if not users: raise CBException( "No users in the commission channel rules whitelist to list.") return Response(embed=discord.Embed(title='Whitelisted users:', description=', '.join( '<@{}>'.format(it) for it in users)))
async def get_response(bot, context): response = Response() use_plugin = configurations.get(bot, __name__, key='enable') if not use_plugin: response.content = ( "The GDQ plugin is currently disabled. (GDQ is probably over or hasn't started yet)") return response embed_template = discord.Embed( title='Games Done Quick', url='https://gamesdonequick.com/', colour=discord.Colour(0x00aff0), description='\[ [Stream]({}) ] \[ [Schedule]({}) ] \[ [Donate]({}) ]'.format( configurations.get(bot, __name__, 'stream_url'), configurations.get(bot, __name__, 'schedule_url'), configurations.get(bot, __name__, 'donate_url'))) embed_template.set_thumbnail(url='http://i.imgur.com/GcdqhUR.png') guild_id = context.guild.id if context.guild else None if context.index == 0: embed_template.add_field(name='Donation stats', value='Loading...', inline=False) response.game_index = data.get(bot, __name__, 'current_index', volatile=True, default=0) schedule_data = data.get(bot, __name__, 'schedule', volatile=True) games_list = schedule_data[response.game_index:response.game_index + 5] game_data = _embed_games_information(bot, games_list, guild_id) value = '\n\n'.join('**{}**\n{}'.format(*it) for it in game_data) embed_template.add_field(name='Schedule', value=value, inline=False) response.update_stats = True response.update_task = None response.message_type = MessageTypes.INTERACTIVE response.extra_function = gdq_menu response.extra = {'buttons': ['⬅', '⏺', '➡']} elif context.index == 1: # About embed_template.add_field(name='About', value=( "Games Done Quick (GDQ) is a week-long charity gaming marathon that " "brings together speedrunners from around the globe to raise money on a " "livestream. They are currently supporting {0}, and all donations go " "directly to the charity.\n\nCheck out the links above for the Twitch " "stream, games schedule, and the donation portal!").format( configurations.get(bot, __name__, 'charity'))) elif context.index == 2: # Status status_text = await _get_status(bot) embed_template.add_field(name='Status', value=status_text, inline=False) elif context.index == 3: # Current game embed_data = _get_current_game(bot, guild_id)[0] embed_template.add_field(name=embed_data[0], value=embed_data[1], inline=False) elif context.index == 4: # Next game(s) embed_data = _get_next_games(bot, context.arguments[0], guild_id) for name, value in embed_data: embed_template.add_field(name=name, value=value, inline=False) elif context.index == 5: # Search embed_data = _search_games(bot, context.arguments[0], guild_id=guild_id) embed_template.add_field(name=embed_data[0], value=embed_data[1], inline=False) elif context.index == 6: # Notify game = _search_games(bot, context.arguments[0], return_game=True) response.content = _toggle_notification( bot, game, context, use_channel='channel' in context.options) embed_template = None response.embed = embed_template return response
async def get_response(bot, context): """Gets a response given the parsed input. context attributes: bot -- A reference to the bot itself. message -- The discord.message object obtained from on_message. base -- The base command name that immediately follows the invoker. subcommand -- The subcommand that matched the parameters. index -- The index of the found subcommand. options -- A dictionary representing the options and potential positional arguments that are attached to them. arguments -- A list of strings that follow the syntax of the blueprint index for arguments following the options. keywords -- Another list of strings that holds all option keywords. These can be used to prevent database conflicts with user commands. cleaned_content -- Simply the message content without the invoker. """ # This is what the bot will say when it returns from this function. # The response object can be manipulated in many ways. The attributes of # the response will be passed into the send function. response = Response() response.content = '' # Default # Set to True if you want your message read with /tts (not recommended). response.tts = False # Default # The message type dictates how the bot handles your returned message. # # NORMAL - Normal. The issuing command can be edited. # PERMANENT - Message is not added to the edit dictionary. # REPLACE - Deletes the issuing command after 'extra' seconds. Defaults # to 0 seconds if 'extra' is not given. # ACTIVE - The message reference is passed back to the function defined # with 'extra_function'. If 'extra_function' is not defined, it will call # plugin.handle_active_message. # INTERACTIVE - Assembles reaction buttons given by extra['buttons'] and # calls 'extra_function' whenever one is pressed. # WAIT - Wait for event. Calls 'extra_function' with the result, or None # if the wait timed out. # # Only the NORMAL message type can be edited. response.message_type = MessageTypes.NORMAL # Default # The extra variable is used for some message types. response.extra = None # Default # Initially, check to make sure that you've matched the proper command. # If there is only one command specified, this may not be necessary. index, options, arguments = context.index, context.options, context.arguments if context.base == 'mycommand': # Then, the subcommand index will tell you which command syntax was # satisfied. The order is the same as was specified initially. if index == 0: # myoption response.content = "You called the first subcommand!" # Do other stuff... elif index == 1: # custom/attached # To see if an optional option was included in the command, use: if 'custom' in options: response.content += "You included the \"custom\" flag!\n" # Do stuff relevant to this flag here... # To get the parameter attached to an option, simply access it from # the options dictionary. if 'attached' in options: response.content += "The attached parmeter: {}\n".format(options['attached']) # In case somebody was looking for the help... if len(options) == 0: invoker = utilities.get_invoker(bot, guild=context.guild) response.content += ("You didn't use either flag...\n" "For help, try `{}help mycommand`".format(invoker)) elif index == 2: # trailing arguments # If arguments are specified as trailing, they will be in a list. response.content += "The list of trailing arguments: {}".format(arguments) elif index == 3: # grouped arguments # All arguments are grouped together as the first element response.message_type = MessageTypes.PERMANENT response.content = ("You can't edit your command here.\n" "Single grouped argument: {}").format(arguments[0]) elif index == 4: # complex # This mixes elements of both examples seen above. response.content = ("The argument attached to the complex " "option: {}").format(options['complex']) if 'other' in options: response.content += "\nThe other option has attached: {}".format(options['other']) response.content += "\nLastly, the trailing arguments: {}".format(arguments) elif index == 5: # (Very slow) marquee # This demonstrates the active message type. # Check active_marquee to see how it works. response.message_type = MessageTypes.ACTIVE response.extra_function = active_marquee # The function to call response.extra = arguments[0] # The text to use response.content = "Setting up marquee..." # This will be shown first # Here's another command base. elif context.base == 'myothercommand': if index == 0: # keyword checker text = arguments[0] if not text: response.content = "You didn't say anything...\n" else: response.content = "This is your input: {}\n".format(text) if text in context.keywords: response.content += "Your input was in the list of keywords!\n" else: response.content += ("Your input was not in the list of keywords. " "They are: {}\n").format(context.keywords) response.message_type = MessageTypes.PERMANENT response.delete_after = 15 response.content += "This message will self destruct in 15 seconds." else: # impossible command??? raise CBException("This is a bug! You should never see this message.") elif context.base == 'wait': response.message_type = MessageTypes.WAIT # The extra attribute should consist of a dictionary containing the # event and any other kwargs. Most notably, you will likely want to # define the check used in wait_for. response.extra_function = custom_interaction response.extra = { 'event': 'message', 'kwargs': { 'timeout': 30, # Default 300 'check': lambda m: m.author == context.author, } } response.content = "Say something, {}.".format(context.author) return response