From 0086a21e9aa5f7682d3efd56451bbcbb323b58a8 Mon Sep 17 00:00:00 2001 From: Conner Harkness Date: Tue, 1 Jul 2025 14:38:39 -0600 Subject: [PATCH] Pushing up initial version of bot --- .gitignore | 3 + bot.py | 183 ++++++++++++++++++++++++++++++++++++ py-discord-role-selector.sh | 16 ++++ 3 files changed, 202 insertions(+) create mode 100644 .gitignore create mode 100644 bot.py create mode 100644 py-discord-role-selector.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1812f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/venv/ +/guilds/ +token.txt diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..70b68ee --- /dev/null +++ b/bot.py @@ -0,0 +1,183 @@ +import re +import json +import os +import asyncio +import shutil +import discord + +from pathlib import Path + +intents = discord.Intents(messages=True, guilds=True, message_content=True, reactions=True) +client = discord.Client(intents=intents) +settings = {} + +def touch(input_path): + path = Path(input_path) + path.parent.mkdir(parents=True, exist_ok=True) + path.touch(exist_ok=True) + + +@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) + args = msg.content.split(" ") + tree = f"guilds/{guild.id}" + stub = f"{tree}/{member.id}" + + if len(args) > 0: + + if args[0] == ".register": + if member.guild_permissions.administrator: + touch(stub) + + await msg.add_reaction("✅") + await asyncio.sleep(10) + await msg.delete() + + return + + if args[0] == ".revoke": + if member.guild_permissions.administrator: + shutil.rmtree(tree) + + await msg.add_reaction("✅") + await asyncio.sleep(10) + await msg.delete() + + return + + + + + if len(args) > 1: + # Handle .color command: + if args[0] == ".color": + color = args[1] + existing_role = None + color_regex = r"^#[A-Fa-f0-9]{6}$" + + # Discord treats all zeroes as transparent: + if color.lower() == "#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) + + # 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.lower(): + existing_role = role + continue + + 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() + + + if args[0] == ".new": + role_name = args[1] + + if member.guild_permissions.administrator: + new_role = await guild.create_role(name=role_name) + await new_role.edit(position=bot.top_role.position - 1) + await msg.add_reaction("✅") + await asyncio.sleep(10) + await msg.delete() + + return + + +async def on_raw_reaction_add_or_remove(rxn, add=True): + print("Reaction add or remove?") + print(rxn) + + 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_id = msg.author.id + tree = f"guilds/{guild.id}" + stub = f"{tree}/{author_id}" + + if not os.path.exists(stub): + return + + + #if re.match(r"^Roles:", msg.content, re.IGNORECASE): + if client.user in msg.mentions: + lines = msg.content.split("\n") + found_line = None + + for line in lines: + if rxn.emoji.name in line: + print("REACTION FOUND IN STR") + found_line = line + break + + role_id = re.search(r"<@&([0-9]{1,})>", found_line) + + if role_id is not None: + role_id = int(role_id.group(1)) + + role = await guild.fetch_role(role_id) + member = await guild.fetch_member(rxn.user_id) + + if member.bot: + return + + if add: + await msg.add_reaction(rxn.emoji.name) + await member.add_roles(role) + else: + await 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) + +@client.event +async def on_ready(): + print("READY.") + +def main(): + token = None + with open("token.txt") as f: + token = f.read() + client.run(token) + +if __name__ == "__main__": + main() diff --git a/py-discord-role-selector.sh b/py-discord-role-selector.sh new file mode 100644 index 0000000..99ea8d9 --- /dev/null +++ b/py-discord-role-selector.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +if [[ ! -d ./venv ]] +then + python -m venv venv || python3 -m venv venv || ( + echo "Cannot create a virtual environment" + exit 1 + ) +fi + +source ./venv/Scripts/activate +source ./venv/bin/activate + +pip install discord.py + +python -u bot.py