async def recolor(self, ctx, *, query): """Change the way a color looks.""" colors = db.get(ctx.guild.id, "colors") try: before, after = query.split("|") except ValueError: raise UserInputError( "Command should be formatted as: $rename <color> | <hexcode>") # Find the correct color to remove. or dont. color = utils.color_lookup(before.strip(), colors) if not color: raise UserInputError("Couldn't find that color") after = after.strip() if not utils.validate_hex(after): raise UserInputError( "Invalid hexcode. Get help at https://htmlcolorcodes.com/") # adjust roles if color is changed if color["role"]: role = ctx.guild.get_role(color["role"]) new_color = utils.to_rgb(after) await role.edit(color=discord.Color.from_rgb(*new_color)) # update database db.guilds.update_one({ "_id": ctx.guild.id, "colors": color }, {"$set": { "colors.$.hexcode": after }}) await ctx.invoke(bot.get_command("colors"))
async def rename_theme(self, ctx, *, query): """Rename a theme in the guild.""" themes = db.get(ctx.guild.id, "themes") try: before, after = query.split("|") except ValueError: raise UserInputError( "Command should be formatted as: $t.rn <theme> | <name>") # Find the correct color to remove. or dont. theme = theme_lookup(before.strip(), themes) if not theme: raise UserInputError("Couldn't find that theme") after = after.strip() if not after: raise UserInputError( "Command should be formatted as: $rename <color> | <name>") db.guilds.update_one({ "_id": ctx.guild.id, "themes": theme }, {"$set": { "themes.$.name": after }}) await ctx.invoke(self.bot.get_command("themes"))
async def rename_color(self, ctx, *, query): """Rename a color.""" colors = db.get(ctx.guild.id, "colors") try: before, after = query.split("|") except ValueError: raise UserInputError( "Command should be formatted as: $rename <color> | <name>") # Find the correct color to remove. or dont. color = utils.color_lookup(before.strip(), colors) if not color: raise UserInputError("Couldn't find that color") after = after.strip() if not after: raise UserInputError( "Command should be formatted as: $rename <color> | <name>") # adjust roles if color is changed if color["role"]: role = ctx.guild.get_role(color["role"]) await role.edit(name=after) # update database db.guilds.update_one({ "_id": ctx.guild.id, "colors": color }, {"$set": { "colors.$.name": after }}) await ctx.invoke(bot.get_command("colors"))
async def color_user(self, ctx, member: discord.Member, *, cstring=""): """Color a specified user a specified color.""" colors = db.get(ctx.guild.id, "colors") ucolor = utils.find_user_color(member, colors) if not colors: raise CommandError("There are no active colors") # to eliminate random coloring the same color if len(colors) > 1 and not cstring: exclusive_colors = [color for color in colors if color != ucolor] color = utils.color_lookup(cstring, exclusive_colors) else: color = utils.color_lookup(cstring, colors) if not color: raise CommandError("Color Not Found") if color == ucolor: raise CommandError(f"{member.name} already has that color") # attempt to uncolor and then color user if ucolor: await self.uncolor(member, ucolor) await self.color(member, color) embed = discord.Embed( title=f"{member.name} is {color['name']} {check_emoji()}", color=utils.discord_color(color) ) await ctx.send(embed=embed)
async def show_colors(self, ctx): """Display an image of equipped colors.""" colors = db.get(ctx.guild.id, "colors") if not colors: return await ctx.send(embed=Embed(title="You have no colors")) await ctx.send(file=self.draw_colors(colors))
async def convert(self, ctx, arg): """Find a color in a list of colors based on a query""" colors = db.get(ctx.guild.id, "colors") if not colors: raise CommandError("You have no active colors") color = color_lookup(arg, colors) if not color: raise CommandError("Color Not Found") return color
async def convert(self, ctx, arg): themes = db.get(ctx.guild.id, "themes") if not themes: raise CommandError("You have no themes") theme = theme_lookup(arg, themes) if not theme: raise CommandError("Theme Not Found") return theme
async def show_themes_in_detail(self, ctx): """Shows a detailed, textbased view of your themes.""" themes = db.get(ctx.guild.id, "themes") themes_embed = Embed(title="Themes in Detail", description="") for theme in themes: colors = [ f"**{color['name']}**: {color['hexcode']}" for color in theme["colors"] ] themes_embed.add_field(name=theme["name"], value="\n".join(colors)) await ctx.send(embed=themes_embed)
async def show_themes(self, ctx): """Draw the guild's themes and send in channel.""" themes = db.get(ctx.guild.id, "themes") if not themes: return await ctx.send(embed=Embed(title="You have no themes")) theme_files = self.draw_themes(themes) # create and send catalog catalog = Catalog(theme_files) await catalog.send(ctx.channel)
async def color_server(self, ctx, *, color: utils.ColorConverter = None): """Gather all of the uncolored users and assigns them a color""" output_suppressed = ctx.guild.id in cfg.suppress_output colors = db.get(ctx.guild.id, "colors") # Fetch colors if not colors: raise CommandError("There are no active colors") cfg.heavy_command_active.add(ctx.guild.id) # begin heavy command # get uncolored members uncolored = [member for member in ctx.guild.members if not utils.find_user_color(member, colors)] # Send working message if not output_suppressed: embed = discord.Embed(title=f"Creating Roles {loading_emoji()}") msg = await ctx.send(embed=embed) # color generator for splashing colors = [color] if color else colors # One color needed if color arg index = random.randrange(len(colors)) # random index in colors sliced_colors = colors[index:] + colors[:index] # Loop over all colors that will be applied and create roles for color in sliced_colors[:len(uncolored)]: if not color["role"]: role = await self.create_role(ctx.guild, color) color["role"] = role.id # Send progress update if not output_suppressed: embed = discord.Embed( title=f"Coloring {len(uncolored)} People {loading_emoji()}", description=f"This will take around {len(uncolored)} seconds" ) await msg.edit(embed=embed) # Loop and color every member sleeping a bit inbetween for color, member in zip(cycle(sliced_colors), uncolored): await self.color(member, color) await asyncio.sleep(1) cfg.heavy_command_active.discard(ctx.guild.id) # Send success message if not output_suppressed: embed = discord.Embed( title=f"Colored {len(uncolored)} members {check_emoji()}", color=discord.Color.green() ) await msg.edit(embed=embed)
async def uncolorme(self, ctx): """Display an image of equipped colors.""" colors = db.get(ctx.guild.id, "colors") ucolor = utils.find_user_color(ctx.author, colors) # remove color if ucolor: await self.uncolor(ctx.author, ucolor) response = f"You have been uncolored {check_emoji()}" else: response = "You don't have a color" await ctx.send(embed=discord.Embed(title=response))
async def show_colors_in_detail(self, ctx): """Show what the database thinks colors are (For testing/support).""" colors = db.get(ctx.guild.id, "colors") cinfo = Embed(title="Detailed Color Info", description="") for color in colors: members = [bot.get_user(id).name for id in color["members"]] cinfo.add_field( name=color["name"], value= f"**ROLE:** {color['role']}\n**MEMBERS({len(members)}):** {', '.join(members)}" ) await ctx.send(embed=cinfo)
async def uncolor_server(self, ctx): """Remove all colors but not delete them.""" colors = db.get(ctx.guild.id, "colors") cfg.heavy_command_active.add(ctx.guild.id) # begin heavy command # Remove every role associated with a color for color in colors: if color["role"]: role = ctx.guild.get_role(color["role"]) await role.delete() cfg.heavy_command_active.discard(ctx.guild.id) # end heavy cmd # Send success message if ctx.guild.id not in cfg.suppress_output: embed = discord.Embed(title=f"Everyone has been uncolored {check_emoji()}", color=discord.Color.green()) await ctx.send(embed=embed)
async def clear_colors(self, ctx): """Removes all active colors.""" colors = db.get(ctx.guild.id, "colors") if ctx.guild.id not in cfg.suppress_output: msg = await ctx.send(embed=discord.Embed( title=f"Clearing colors {loading_emoji()}")) # remove roles for color in colors: if color["role"]: role = ctx.guild.get_role(color["role"]) await role.delete() await asyncio.sleep(0.25) db.guilds.update_one({"_id": ctx.guild.id}, {"$set": {"colors": []}}) if ctx.guild.id not in cfg.suppress_output: await msg.edit( embed=discord.Embed(title=f"Colors Removed {check_emoji()}", color=discord.Color.green()))
async def add_color(self, ctx, hexcode, *, name=""): """Add a color to the database colors.""" colors = db.get(ctx.guild.id, "colors") if len(colors) >= cfg.color_limit: raise CommandError(f"Color Limit Reached ({len(colors)}/50)") if not utils.validate_hex(hexcode): raise UserInputError( f"Invalid hexcode. Get help at https://htmlcolorcodes.com/") if "|" in name or len(name) > 100: raise UserInputError( "Color names must be shorter than 100 characters and cannot include `|`" ) if name in [color["name"] for color in colors]: raise UserInputError("Cannot have duplicate color names") # auto name if name not given if not name: name = f"Color {len(colors) + 1}" # change black color because #000000 in discord is transparent if hexcode in {"#000000", "#000"}: hexcode = "#000001" # create and add color new_color = { "name": name, "hexcode": hexcode, "role": None, "members": [] } # update database db.guilds.update_one({"_id": ctx.guild.id}, {"$push": { "colors": new_color }}) await ctx.invoke(bot.get_command("colors")) # show new set
async def import_colors(self, ctx, *, name): """Save a preset as a theme.""" themes = db.get(ctx.guild.id, "themes") if len(themes) >= cfg.theme_limit: raise CommandError(f"Theme Limit Reached ({len(themes)}/10)") # Read in preset as dict name = name.replace(" ", "") try: with open(f"assets{sep}presets{sep}{name.lower()}.json" ) as preset_data: preset = json.load(preset_data) except FileNotFoundError: raise UserInputError("Could not find that preset") db.guilds.update_one({"_id": ctx.guild.id}, {"$push": { "themes": preset }}) if ctx.guild.id not in cfg.suppress_output: await ctx.invoke(self.bot.get_command("themes"))
async def load_theme(self, ctx, *, themename): """Change the active colors to a theme.""" themes = db.get(ctx.guild.id, "themes") theme = theme_lookup(themename, themes) output_suppressed = ctx.guild.id in cfg.suppress_output if not theme: raise UserInputError("Could not find that theme") if not output_suppressed: embed = discord.Embed(title=f"Clearing Colors {loading_emoji()}") msg = await ctx.send(embed=embed) # Supress output from clear_colors and prevent other commands from modifying colors cfg.heavy_command_active.add(ctx.guild.id) cfg.suppress_output.add(ctx.guild.id) await ctx.invoke(self.bot.get_command("clear_colors")) # clear colors if not output_suppressed: cfg.suppress_output.discard(ctx.guild.id) # Progress update embed = discord.Embed(title=f"Creating Roles {loading_emoji()}") await msg.edit(embed=embed) # kind of a monster and probably impractical but it works # keeps only colors that have members that can be found owned_colors = [ color for color in theme["colors"] if color["members"] and all([ ctx.guild.get_member(member_id) for member_id in color["members"] ]) ] # Update colors in db colors = deepcopy(theme["colors"]) for color in colors: color["role"] = None color["members"] = [] db.guilds.update_one({"_id": ctx.guild.id}, {"$set": { "colors": colors }}) cm_pairs = [] # Color and Member pairs for color in owned_colors: # create role role = await ColorAssignment.create_role(ctx.guild, color) color["role"] = role.id # add to color member pair for member_id in color["members"]: cm_pairs.append((color, ctx.guild.get_member(member_id))) # Progress update if not output_suppressed: embed = discord.Embed(title=f"Applying Color {loading_emoji()}") await msg.edit(embed=embed) # loop and apply colors for color, member in cm_pairs: await ColorAssignment.color(member, color) await asyncio.sleep(1) cfg.heavy_command_active.discard(ctx.guild.id) # report success if ctx.guild.id not in cfg.suppress_output: success_embed = discord.Embed( title=f"Loaded {theme['name']} {check_emoji()}", color=discord.Color.green()) await msg.edit(embed=success_embed) await ctx.invoke(self.bot.get_command("colors"))