import re import json import os import asyncio import shutil import discord intents = discord.Intents(messages=True, guilds=True, message_content=True, reactions=True, members=True) client = discord.Client(intents=intents) settings = {} @client.event async def on_ready(): print("READY.") @client.event async def on_message(msg): chl = await client.fetch_channel(msg.channel.id) msg = await chl.fetch_message(msg.id) guild = await client.fetch_guild(chl.guild.id) member = await guild.fetch_member(msg.author.id) bot = await guild.fetch_member(client.user.id) arg_str = msg.content arg_str = re.sub(r"\s{1,}", " ", arg_str) args = arg_str.split(" ") cmd = args.pop(0) arg_str = arg_str.lstrip(cmd).strip() # Allow creating quick roles: if cmd == ".new": if len(arg_str) > 0: if member.guild_permissions.administrator: new_role = await guild.create_role(name=arg_str) await new_role.edit(position=bot.top_role.position - 1) await msg.delete() return # Allow users to change their own color: if cmd == ".color": if len(args) > 0: color = args[0].lower() print(color) existing_role = None color_regex = r"^#[A-Fa-f0-9]{6}$" # Discord treats all zeroes as transparent: if color == "#000000": color = "#010101" if not re.search(color_regex, color): await msg.add_reaction("❌") await asyncio.sleep(10) await msg.delete() return # Remove any previously assigned color roles: for role in member.roles: if re.search(color_regex, role.name): await member.remove_roles(role) # Cache the members early: members = [member async for member in guild.fetch_members(limit=None)] # Iterate through all guild roles, find existing role, and delete those without members: for role in guild.roles: if not re.match(color_regex, role.name): continue if role.name.lower() == color: existing_role = role break # Build a list of role members by iterating through members: role_members = [m for m in members if role in m.roles] if len(role_members) < 1: try: await role.delete(reason="Role contains no more members.") except: pass if existing_role is None: color_value = discord.Color(int(color.strip("#"), 16)) existing_role = await guild.create_role(name=color, color=color_value) await existing_role.edit(position=bot.top_role.position - 1) await member.add_roles(existing_role) await msg.delete() # Handle both reaction events: async def on_raw_reaction_add_or_remove(rxn, add=True): guild_id = rxn.guild_id channel_id = rxn.channel_id message_id = rxn.message_id guild = await client.fetch_guild(guild_id) chl = await client.fetch_channel(rxn.channel_id) msg = await chl.fetch_message(rxn.message_id) author_member = await guild.fetch_member(msg.author.id) user_member = await guild.fetch_member(rxn.user_id) # Exit early if: if not author_member.guild_permissions.administrator: return if user_member.bot: return if client.user in msg.mentions: lines = msg.content.split("\n") found_line = None for line in lines: if rxn.emoji.name in line: found_line = line break role_id = re.search(r"<@&([0-9]{1,})>", found_line) role_id = int(role_id.group(1)) if role_id is not None else None if role_id is None: return role = await guild.fetch_role(role_id) if add: await msg.add_reaction(rxn.emoji.name) await user_member.add_roles(role) else: await user_member.remove_roles(role) @client.event async def on_raw_reaction_add(rxn): await on_raw_reaction_add_or_remove(rxn, True) @client.event async def on_raw_reaction_remove(rxn): await on_raw_reaction_add_or_remove(rxn, False) def main(): token = None with open("token.txt") as f: token = f.read() client.run(token) if __name__ == "__main__": main()