async def _courses_create(self, ctx, role: str, *, sections_num: int = 0): """ Creates a category based on the course name supplied. If the role for the course doesn't exist it will query to user if it should be created as well. """ if role == "": return await ctx.send(error("Role cannot be blank")) role = role.lower() sections_num = max(sections_num, 0) # regisiter the course with the database await self._courses_register(ctx, role, sort=True) await ctx.channel.send("Done.")
async def _save_public_private( self, ctx: commands.Context, autoroom_source: discord.VoiceChannel, room_type: str, ): """Save the public/private setting.""" async with self.config.guild(ctx.guild).auto_voice_channels() as avcs: try: avcs[str(autoroom_source.id)]["room_type"] = room_type except KeyError: await ctx.send( error("{} is not an AutoRoom Source channel.".format( autoroom_source.mention))) else: await ctx.send( checkmark("New AutoRooms created by {} will be {}.".format( autoroom_source.mention, room_type)))
async def max_requestable(self, ctx, count: int): """Maximum number of roles that users can request. If set to -1, there is no limit.""" if count < -1: await self._raw_send_no_mention( ctx, error("Maximum must not be negative.")) await self.config.guild(ctx.guild).max_requestable.set(count) if count == -1: count_str = "unlimited" else: count_str = str(count) await self._raw_send_no_mention( ctx, info("The maximum number of requestable roles per user is now {}.". format(count_str)))
async def modify_text_enable( self, ctx: commands.Context, autoroom_source: discord.VoiceChannel, ): """Enable creating a text channel with the AutoRoom.""" if await self.get_autoroom_source_config(autoroom_source): await self.config.custom("AUTOROOM_SOURCE", ctx.guild.id, autoroom_source.id).text_channel.set(True) await ctx.send( checkmark( f"New AutoRooms created by **{autoroom_source.mention}** will now get their own text channel." )) else: await ctx.send( error( f"**{autoroom_source.mention}** is not an AutoRoom Source channel." ))
async def skin(self, ctx, player: MCPlayer, overlay: bool = True): """Get minecraft skin by nickname""" uuid = player.uuid stripname = player.name.strip("_") files = [] async with ctx.channel.typing(): try: async with self.session.get( f"https://crafatar.com/renders/head/{uuid}", params="overlay" if overlay else None, ) as s: files.append( discord.File(BytesIO(await s.read()), filename=f"{stripname}_head.png")) async with self.session.get( f"https://crafatar.com/skins/{uuid}") as s: files.append( discord.File(BytesIO(await s.read()), filename=f"{stripname}.png")) async with self.session.get( f"https://crafatar.com/renders/body/{uuid}.png", params="overlay" if overlay else None, ) as s: files.append( discord.File(BytesIO(await s.read()), filename=f"{stripname}_body.png")) except aiohttp.ClientResponseError as e: await ctx.send( chat.error( _("Unable to get data from Crafatar: {}").format( e.message))) return em = discord.Embed(timestamp=ctx.message.created_at, color=await ctx.embed_color()) em.set_author( name=player.name, icon_url=f"attachment://{stripname}_head.png", url=f"https://crafatar.com/skins/{uuid}", ) em.set_thumbnail(url=f"attachment://{stripname}.png") em.set_image(url=f"attachment://{stripname}_body.png") em.set_footer(text=_("Provided by Crafatar"), icon_url="https://crafatar.com/logo.png") await ctx.send(embed=em, files=files)
async def modify_text_hint_disable( self, ctx: commands.Context, autoroom_source: discord.VoiceChannel, ): """Disable sending a message to the newly generated text channel.""" if await self.get_autoroom_source_config(autoroom_source): await self.config.custom( "AUTOROOM_SOURCE", ctx.guild.id, autoroom_source.id).text_channel_hint.clear() await ctx.send( checkmark( f"New AutoRooms created by **{autoroom_source.mention}** will no longer have a message sent to their text channel." )) else: await ctx.send( error( f"**{autoroom_source.mention}** is not an AutoRoom Source channel." ))
async def rolls(self, ctx: commands.Context, maximum: int): """Set the maximum number of dice a user can roll at one time. More formally, the maximum number of random numbers the bot will generate for any one dice calculation. WARNING: Setting this too high will allow other users to slow down/freeze/crash your bot! Generating random numbers is easily the most CPU consuming process here, so keep this number low (less than one million, and way less than that on a Pi) """ action = "is already set at" if maximum == await self.config.max_dice_rolls(): pass elif maximum > 1000000: pred = MessagePredicate.yes_or_no(ctx) await ctx.send( question( f"Are you **sure** you want to set the maximum rolls to {maximum}? (yes/no)\n" "Setting this over one million will allow other users to slow down/freeze/crash your bot!" ) ) try: await ctx.bot.wait_for("message", check=pred, timeout=30) except asyncio.TimeoutError: pass if pred.result: await self.config.max_dice_rolls.set(maximum) action = "is now set to" else: await ctx.send( error( f"Maximum dice rolls per user has been left at {await self.config.max_dice_rolls()}" ) ) return else: await self.config.max_dice_rolls.set(maximum) action = "is now set to" await ctx.send( checkmark( f"Maximum dice rolls per user {action} {await self.config.max_dice_rolls()}" ) )
async def predicate(ctx: commands.Context): if ( not ctx.guild or ctx.channel.is_nsfw() or ctx.invoked_with == "help" or ctx.invoked_subcommand ): return True if ctx.invoked_with not in [k for k in ctx.bot.all_commands]: # For this weird issue with last version of discord.py (1.2.3) with non-existing commands. # So this check is only for dev version of Red. # https://discordapp.com/channels/133049272517001216/133251234164375552/598149067268292648 for reference. # It probably need to check in d.py to see what is happening, looks like an issue somewhere. # It will probably removed in the future, it's a temporary check. return False try: await ctx.send(chat.error(_("You can't use this command in a non-NSFW channel!"))) finally: return False
async def clear(self, ctx): """Clears all requestable roles.""" # requestable list role_subset = await self.config.guild(ctx.guild).roles() role_objs = [x for x in ctx.author.roles if x.id in role_subset] role_count = len(role_objs) if role_count > 0: await ctx.author.remove_roles(*role_objs) if role_count > 1: await ctx.send( "Removed {num} of your roles.".format(num=role_count)) else: await ctx.send("Removed {r} from your roles.".format( r=await self._get_role_styled(ctx, role_objs[0]))) if await self.config.guild(ctx.guild).auto_post_list(): await self._auto_post_list(ctx) else: await ctx.send( error("You do not have any requestable roles to remove."))
async def colour(self, ctx, *, colour: discord.Colour = discord.Colour.default()): """Change color of personal role""" role = await self.config.member(ctx.author).role() role = ctx.guild.get_role(role) try: await role.edit(colour=colour, reason=get_audit_reason(ctx.author, "Personal Role")) except discord.Forbidden: await ctx.send( chat.error( "Unable to edit role.\nRole must be lower than my top role and i must have " "permission \"Manage Roles\"")) else: await ctx.send("Changed color of {}'s personal role to {}".format( ctx.message.author.name, colour))
async def dice(self, ctx: commands.Context, *, roll: str): """Perform die roll based on a dice formula. The [PyHedrals](https://github.com/StarlitGhost/pyhedrals) library is used for dice formula parsing. Use the link above to learn the notation allowed. Below are a few examples: `2d20kh` - Roll 2d20, keep highest die (e.g. initiative advantage) `4d4!+2` - Roll 4d4, explode on any 4s, add 2 to result `4d6rdl` - Roll 4d6, reroll all 1s, then drop the lowest die `6d6c>4` - Roll 6d6, count all dice greater than 4 as successes `10d10r<=2kh6` - Roll 10d10, reroll all dice less than or equal to 2, then keep the highest 6 dice Modifier order does matter, and usually they allow for specifying a specific number or number ranges after them. """ try: dr = pyhedrals.DiceRoller( maxDice=await self.config.max_dice_rolls(), maxSides=await self.config.max_die_sides(), ) result = dr.parse(roll) roll_message = f"\N{GAME DIE} {ctx.message.author.mention} rolled {roll} and got **{result.result}**" if len(roll_message) > 2000: raise ValueError( "resulting roll message is too big to send in Discord") roll_log = "\n".join(result.strings()) roll_log = self.DROPPED_EXPLODED_RE.sub(r"~~**\1!**~~", roll_log) roll_log = self.EXPLODED_RE.sub(r"**\1!**", roll_log) roll_log = self.DROPPED_RE.sub(r"~~\1~~", roll_log) roll_log = roll_log.replace(",", ", ") if len(roll_message) + len(roll_log) > 2000: roll_log = "*(Roll log too long to display)*" await ctx.send(f"{roll_message}\n{roll_log}") except ( ValueError, NotImplementedError, pyhedrals.InvalidOperandsException, pyhedrals.SyntaxErrorException, pyhedrals.UnknownCharacterException, ) as exception: await ctx.send( error( f"{ctx.message.author.mention}, I couldn't parse your dice formula:\n`{str(exception)}`" ))
async def rule_set(self, ctx, rule_num: int = None, *, rule: str = None): """ Set a guild rule Will overwrite an existing rule of the same number. """ if ctx.invoked_subcommand: return elif rule_num is not None and rule is not None: async with self.config.guild(ctx.guild).rules() as rules: rules[str(rule_num)] = rule await ctx.tick() elif rule_num is not None: rules = await self.config.guild(ctx.guild).rules() try: await ctx.send(rules[str(rule_num)]) except KeyError: await ctx.send(chat.error("That rule doesn't exist!")) else: await self.bot.send_help_for(ctx, self.rule_set)
async def embedwiz_edit(self, ctx, message_id: int, *, specification): """ Edits an existing embed according to the spec. See [p]help embedwiz for more information. """ channel = ctx.channel #member = channel.server and channel.server.get_member(ctx.message.author.id) #if channel != ctx.message.channel and not member: #await ctx.send(error("Channel is private or you aren't in the server that channel belongs to.")) #return try: msg = await ctx.fetch_message(message_id) #msg = await self.bot.get_message(channel, str(message_id)) except discord.errors.NotFound: await ctx.send(error('Message not found.')) return except discord.errors.Forbidden: await ctx.send(error('No permissions to read that channel.')) return if msg.author.id != self.bot.user.id: await ctx.send(error("That message isn't mine.")) return elif not msg.embeds: await ctx.send(error("That message doesn't have an embed.")) return old_embed = msg.embeds[0] override = 0 #self._check_override(member) if override: pass elif 'author' not in old_embed or 'name' not in old_embed['author']: await ctx.send( error( "That embed doesn't have an author set, and you aren't a mod or admin." )) return elif old_embed['author']['name'].split( '(')[-1][:-1] != ctx.message.author.id: await ctx.send(error("That embed isn't yours.")) return new_embed = await self._parse_embed(ctx, specification, force_author=not override) await self.bot.edit_message(msg, embed=new_embed) await ctx.send('Embed edited successfully.')
async def cleanup_users(self, ctx, days: Optional[int] = 1, *roles: discord.Role): """Cleanup inactive server members""" if days > 30: await ctx.send( chat.info( _("Due to Discord Restrictions, you cannot use more than 30 days for that cmd." ))) days = 30 elif days <= 0: await ctx.send(chat.info(_('"days" arg cannot be less than 1...'))) days = 1 to_kick = await ctx.guild.estimate_pruned_members(days=days) pred = MessagePredicate.yes_or_no(ctx) if not ctx.assume_yes: roles_text = _("\nIncluding members in roles: {}\n").format( ", ".join(r.mention for r in roles)) await ctx.send( chat.warning( _("You are about to kick **{to_kick}** inactive for **{days}** days members from this server. " '{roles}Are you sure?\nTo agree, type "yes"').format( to_kick=to_kick, days=days, roles=roles_text if roles else ""))) try: await self.bot.wait_for("message", check=pred, timeout=30) except AsyncTimeoutError: pass if ctx.assume_yes or pred.result: cleanup = await ctx.guild.prune_members(days=days, reason=get_audit_reason( ctx.author), roles=roles or None) await ctx.send( chat.info( _("**{removed}**/**{all}** inactive members removed.\n" "(They were inactive for **{days}** days)").format( removed=cleanup, all=to_kick, days=days))) else: await ctx.send(chat.error(_("Inactive members cleanup canceled.")))
async def _save_room_name( self, ctx: commands.Context, autoroom_source: discord.VoiceChannel, room_type: str, ): """Save the room name type.""" async with self.config.guild(ctx.guild).auto_voice_channels() as avcs: try: avcs[str(autoroom_source.id)]["channel_name_type"] = room_type except KeyError: await ctx.send( error( f"**{autoroom_source.mention}** is not an AutoRoom Source channel." )) else: await ctx.send( checkmark( f"New AutoRooms created by **{autoroom_source.mention}** " f"will use the **{room_type.capitalize()}** format."))
async def service_disable(self, ctx: commands.Context, service: str): """Disable a service.""" disabled_services = await self.config.guild(ctx.message.guild ).disabled_services() if service in self.supported_services and service in disabled_services: await ctx.send( info("{} is already disabled for this guild.".format( self.get_nice_service_name(service)))) elif service in self.supported_services: disabled_services.append(service) await self.config.guild(ctx.message.guild ).disabled_services.set(disabled_services) await ctx.send( checkmark( "Ban checking with {} has now been disabled for this guild!" .format(self.get_nice_service_name(service)))) else: await ctx.send( error("`{}` is not a valid service name.".format( self.get_nice_service_name(service))))
async def _save_public_private( self, ctx: commands.Context, autoroom_source: discord.VoiceChannel, room_type: str, ): """Save the public/private setting.""" if await self.get_autoroom_source_config(autoroom_source): await self.config.custom( "AUTOROOM_SOURCE", ctx.guild.id, autoroom_source.id).room_type.set(room_type) await ctx.send( checkmark( f"**{autoroom_source.mention}** will now create `{room_type}` AutoRooms." )) else: await ctx.send( error( f"**{autoroom_source.mention}** is not an AutoRoom Source channel." ))
async def addrole(self, ctx, *, role_name): """Adds a role to be requestable.""" # find matches role_to_add = await self._find_role(ctx, role_name) if role_to_add is None: return async with self.config.guild(ctx.guild).roles() as role_subset: if role_to_add.id in role_subset: await ctx.send( error("Role {r} can already be requested.".format( r=await self._get_role_styled(ctx, role_to_add)))) return role_subset.append(role_to_add.id) await ctx.send( info("Added {r} to requestable roles list.".format( r=await self._get_role_styled(ctx, role_to_add)))) if await self.config.guild(ctx.guild).auto_post_list(): await self._auto_post_list(ctx)
async def default(self, ctx: commands.Context, autoroom_source: discord.VoiceChannel): """Reset the increment format back to default. The default format, for those curious, is ` ({number})` (which looks like "Room Name (2)") """ if await self.get_autoroom_source_config(autoroom_source): await self.config.custom( "AUTOROOM_SOURCE", ctx.guild.id, autoroom_source.id).increment_format.clear() await ctx.send( checkmark( f"Channel name increment format for **{autoroom_source.mention}** has been reset to default." )) else: await ctx.send( error( f"**{autoroom_source.mention}** is not an AutoRoom Source channel." ))
async def set_channel(self, ctx: commands.Context, channel: discord.TextChannel = None): """Set the channel you want new user BanCheck notices to go to.""" if channel is None: channel = ctx.message.channel await self.config.guild(ctx.message.guild ).notify_channel.set(channel.id) try: embed = self.embed_maker( None, discord.Colour.green(), checkmark("**I will send all BanCheck notices here.**"), self.bot.user.avatar_url, ) await channel.send(embed=embed) except (discord.errors.Forbidden, discord.errors.NotFound): await channel.send( error("**I'm not allowed to send embeds here.**"))
async def gettinfo( self, ctx: commands.Context, word_type: WordType, word: str, ): try: async with self.session.get(TYPES[word_type]["endpoint"] + word) as session: data = await session.json() except aiohttp.ClientError: await ctx.maybe_send_embed(warning("Failed to connect to the API.")) return else: if not data: if word_type == "ml": message = "No words found for this definition." else: message = "No matches found for this word." return await ctx.maybe_send_embed(error(message)) await self.create_menu(ctx, word_type, word, data)
async def build_karma_view(self, ctx, member: discord.Member): """ Displays a user's karma score. """ if not isinstance(member, discord.Member): try: member = self.bot.get_guild(self.guild_id).get_member( int(member)) except ValueError: msg = f"{member} is not a valid member id." logger.exception(msg) await ctx.send( warning( "Oops, Something went wrong. Ask an **admin** or **bot-dev** to check the log." )) return await self.properties["channels"].log.send(error(msg)) if member is None: return await ctx.send(warning("User not found.")) def build_field(group): return (f"**Current:** {group['current']}\n" f"**All Time:** {group['total']}") try: been_thanked_val = build_field( await self.db.member(member).been_thanked()) thanked_others_val = build_field( await self.db.member(member).thanked_others()) except KeyError: logger.error("Member does not exist.") return None else: embed = discord.Embed(title=f"{member.display_name}'s karma") embed.add_field(name="Thanked by others", value=been_thanked_val, inline=False) embed.add_field(name="Thanked others", value=thanked_others_val, inline=False) return randomize_color(embed)
async def discordstatus(self, ctx): """Get current discord status from discordstatus.com""" async with ctx.typing(): try: async with self.session.get( "https://srhpyqt94yxb.statuspage.io/api/v2/summary.json" ) as data: response = await data.json(loads=json.loads) except Exception as e: await ctx.send( chat.error( _("Unable to get data from https://discordstatus.com: {}" ).format(e))) return status = response["status"] components = response["components"] if await ctx.embed_requested(): embed = discord.Embed( title=_("Discord Status"), description=_( DISCORD_STATUS_NAMES.get(status["indicator"], status["indicator"])), timestamp=datetime.datetime.fromisoformat( response["page"]["updated_at"]).astimezone( datetime.timezone.utc).replace( tzinfo=None), # make naive color=await ctx.embed_color(), url="https://discordstatus.com", ) for component in components: embed.add_field( name=component["name"], value=component["status"].capitalize().replace( "_", " "), ) await ctx.send(embed=embed) else: await ctx.send( f"{_(DISCORD_STATUS_NAMES.get(status['indicator'], status['indicator']))}\n" f"{chat.box(tabulate([(c['name'], c['status'].capitalize().replace('_', ' ')) for c in components]))}" )
async def wikipedia(self, ctx: commands.Context, *, query: str): """Get information from Wikipedia.""" can_not_embed_links = not ctx.channel.permissions_for( ctx.me).embed_links can_not_add_reactions = not ctx.channel.permissions_for( ctx.me).add_reactions can_not_read_history = not ctx.channel.permissions_for( ctx.me).read_message_history only_first_result = (can_not_embed_links or can_not_add_reactions or can_not_read_history) async with ctx.typing(): embeds, url = await self.perform_search( query, only_first_result=only_first_result) if not embeds: await ctx.send( error(f"I'm sorry, I couldn't find \"{query}\" on Wikipedia")) elif can_not_embed_links: await ctx.send( warning( f"I'm not allowed to do embeds here, so here's the first result:\n{url}" )) elif can_not_add_reactions: embeds[0].set_author( name="Result 1 (I need add reactions permission to show more)") await ctx.send(embed=embeds[0]) elif can_not_read_history: embeds[0].set_author( name= "Result 1 (I need read message history permission to show more)" ) await ctx.send(embed=embeds[0]) elif len(embeds) == 1: embeds[0].set_author(name="Result 1 of 1") await ctx.send(embed=embeds[0]) else: count = 0 for embed in embeds: count += 1 embed.set_author(name=f"Result {count} of {len(embeds)}") await menu(ctx, embeds, DEFAULT_CONTROLS, timeout=60.0)
async def wikipedia(self, ctx: commands.Context, *, query: str): """Get information from Wikipedia.""" async with ctx.typing(): payload = self.generate_payload(query) conn = aiohttp.TCPConnector() async with aiohttp.ClientSession(connector=conn) as session: async with session.get( "https://en.wikipedia.org/w/api.php", params=payload, headers={"user-agent": "Red-DiscordBot/" + redbot_version}, ) as res: result = await res.json() embeds = [] if "query" in result and "pages" in result["query"]: for page in result["query"]["pages"]: try: embeds.append(self.generate_embed(page)) if not ctx.channel.permissions_for(ctx.me).embed_links: # No embeds here :( await ctx.send( warning( "I'm not allowed to do embeds here...\n{}".format( page["fullurl"] ) ) ) return if not ctx.channel.permissions_for(ctx.me).add_reactions: break # Menu can't function so only show first result except KeyError: pass if not embeds: await ctx.send( error("I'm sorry, I couldn't find \"{}\" on Wikipedia".format(query)) ) elif len(embeds) == 1: await ctx.send(embed=embeds[0]) else: await menu(ctx, embeds, DEFAULT_CONTROLS, timeout=60.0)
async def _save_channel( self, ctx: commands.Context, channel: Optional[discord.TextChannel], channel_type: Union[str, list], ): """Actually save the ReactChannel settings.""" if channel is None: channel = ctx.message.channel if isinstance(channel_type, list): try: for emoji in channel_type: await ctx.message.add_reaction(emoji) for emoji in channel_type: await ctx.message.remove_reaction(emoji, self.bot.user) except discord.HTTPException: await ctx.send( error( f"{'That' if len(channel_type) == 1 else 'One of those emojis'} is not a valid emoji I can use!" )) return await self.config.custom("REACT_CHANNEL", ctx.guild.id, channel.id).set( {"channel_type": channel_type}) channel_type_name = channel_type custom_emojis = "" if isinstance(channel_type_name, list): channel_type_name = "custom" custom_emojis = f" ({', '.join(channel_type)})" await ctx.send( checkmark( f"{channel.mention} is now a {channel_type_name} ReactChannel.{custom_emojis}" )) if (channel_type == "vote" and not await self._get_emoji(ctx.guild, "upvote") and not await self._get_emoji(ctx.guild, "downvote")): await ctx.send( warning( "You do not have an upvote or downvote emoji set for this server. " "You will need at least one set in order for this ReactChannel to work. " "Check `[p]reactchannelset emoji` for more information."))
async def rot13(self, ctx, *, text): """Encodes text using ROT-13.""" if isinstance(ctx.channel, discord.TextChannel): # this not is a DM or group DM #message = ctx.message #footer = "In channel #{channel} on {guild}".format(channel = ctx.channel, guild = message.guild) #async with ctx.typing(): await ctx.send(content=error( "This is a server channel. The ROT-13 command is supported for direct messages only. The purpose is to make an encoded message." )) #try: # await message.delete() #except (discord.Forbidden, discord.HTTPException): # # permissions to delete here denied # await ctx.send(content=error("This is a public location and I do not have permission to delete your message!")) # return #embed = discord.Embed(description=self._rot13(text)) #if message.author.color != discord.Color.default(): # embed.color = message.author.color #embed.set_author(name=message.author.display_name) #embed.set_thumbnail(url=message.author.avatar_url) #embed.set_footer(text=footer) #embed.timestamp = message.created_at ##await user.send(content=self._rot13(message.clean_content)) #try: # post = await ctx.send(embed=embed) #except (discord.Forbidden, discord.HTTPException): # await ctx.send(content=error("This is a public location and I do not have the ability to post an embed!")) # return #self.embed_cache.append(int(message.id)) #settings = await self.config.guild(message.guild).all() #try: # await post.add_reaction(settings["react"]) #except (discord.NotFound, discord.Forbidden, discord.HTTPException): # pass else: # private location: only reply with text await ctx.send(content=self._rot13(text))
async def autoban_enable(self, ctx: commands.Context, service: str): """Enable a service to ban users automatically.""" if service not in self.all_supported_services: await ctx.send( error("{} is not a valid service name.".format( self.get_nice_service_name(service)))) return async with self.config.guild(ctx.guild).services() as config_services: if service not in config_services: config_services[service] = {} config_services[service]["autoban"] = True config_services[service]["enabled"] = True response = "Automatic banning with {} has now been enabled.".format( self.get_nice_service_name(service)) if not await self.config.guild(ctx.guild).notify_channel(): response += "\nYou will need to set up AutoCheck in order for this to take effect." if not await self.get_api_key(service, config_services): response += "\nAn API key is needed in order for this to take effect." if not ctx.guild.me.guild_permissions.ban_members: response += "\nI will need to be granted the Ban Members permission for this to take effect." await ctx.send(checkmark(response))
async def discordstatus(self, ctx): """Get current discord status from status.discordapp.com""" try: async with self.session.get("https://srhpyqt94yxb.statuspage.io/api/v2/summary.json") as data: response = await data.json() except Exception as e: await ctx.send(chat.error("Unable to get data from https://status.discordapp.com: {}".format(e))) return status = response["status"] status_indicators = {"none": "OK", "minor": "Minor problems", "major": "Major problems", "critical": "Critical problems"} components = response["components"] embed = discord.Embed(title="Discord Status", timestamp=parse(response["page"]["updated_at"]), color=await ctx.embed_color(), url="https://status.discordapp.com") embed.description = status_indicators.get(status["indicator"], status["indicator"]) for component in components: embed.add_field(name=component["name"], value=component["status"].capitalize().replace("_", " ")) await ctx.send(embed=embed)
async def status(self, ctx): """Get status of minecraft services""" try: async with self.session.get( "https://status.mojang.com/check") as data: data = await data.json(loads=json.loads) em = discord.Embed( title=_("Status of minecraft services"), timestamp=ctx.message.created_at, color=await ctx.embed_color(), ) for service in data: for entry, status in service.items(): em.add_field(name=entry, value=_(SERVICE_STATUS.get(status, status))) await ctx.send(embed=em) except Exception as e: await ctx.send( chat.error( _("Unable to check. An error has been occurred: {}"). format(chat.inline(str(e)))))