matchy/matchy.py

112 lines
4 KiB
Python
Raw Normal View History

2024-08-07 22:15:39 +01:00
import discord
2024-08-07 23:23:52 +01:00
import random
2024-08-08 23:32:52 +01:00
import logging
import importlib
from discord import app_commands
from discord.ext import commands
2024-08-08 23:32:52 +01:00
# Config contains
# TOKEN : str - Discord bot token
# SERVERS : list[int] - ids of the servers to have commands active
# OWNERS : list[int] - ids of owners able to use the owner commands
import config
2024-08-07 23:23:52 +01:00
2024-08-09 00:06:23 +01:00
# Set up a logger for matchy
2024-08-08 23:32:52 +01:00
logger = logging.getLogger("matchy")
logger.setLevel(logging.INFO)
2024-08-09 00:06:23 +01:00
# Create the discord commands bot
2024-08-07 22:15:39 +01:00
intents = discord.Intents.default()
intents.message_content = True
2024-08-07 23:23:52 +01:00
intents.members = True
bot = commands.Bot(command_prefix='$', description="Matchy matches matchees", intents=intents)
2024-08-07 22:15:39 +01:00
guilds = []
2024-08-09 00:06:23 +01:00
def cache_guilds():
"""Sync current bot guilds to a list to use"""
guilds = list(g for g in bot.guilds if g.id in config.SERVERS)
logger.info(f"Cached {len(guilds)} guild(s)")
@bot.event
async def on_ready():
2024-08-09 00:06:23 +01:00
"""Cache some info once ready"""
cache_guilds()
2024-08-08 23:32:52 +01:00
logger.info("Bot is up and ready!")
2024-08-07 23:23:52 +01:00
@bot.command()
2024-08-09 00:06:23 +01:00
@commands.check(lambda ctx: ctx.message.author.id in config.OWNERS)
2024-08-09 00:32:59 +01:00
@commands.dm_only()
2024-08-09 00:06:23 +01:00
async def sync(ctx: discord.ext.commands.context.Context):
"""Handle sync command"""
# Reload the config first
importlib.reload(config)
logger.info(f"Reloaded config")
2024-08-09 00:06:23 +01:00
# Sync the commands with the discord API
synced = await bot.tree.sync()
2024-08-08 23:32:52 +01:00
logger.info(f"Synced {len(synced)} command(s)")
2024-08-09 00:06:23 +01:00
# Cache the guild information
cache_guilds()
await ctx.reply("Done!", ephemeral=True)
2024-08-09 14:12:28 +01:00
@bot.tree.command(description = "Match matchees into groups", guilds = list(g for g in guilds if g.id in config.SERVERS))
@app_commands.describe(per_group = "Matchees per group (default 3+)", post = "Post to channel")
2024-08-09 00:32:59 +01:00
@commands.guild_only()
async def match(interaction: discord.Interaction, per_group: int = None, post: bool = None):
2024-08-09 00:06:23 +01:00
"""Match groups of channel members"""
2024-08-09 00:16:51 +01:00
if not per_group:
per_group = 3
2024-08-09 14:12:28 +01:00
2024-08-08 23:32:52 +01:00
logger.info(f"User {interaction.user} requested /match {per_group}")
# Grab the roles
2024-08-09 00:06:23 +01:00
matchee_role = next(r for r in interaction.guild.roles if r.name == "Matchee")
matcher_role = next(r for r in interaction.guild.roles if r.name == "Matcher")
2024-08-08 23:32:52 +01:00
if not matchee_role or not matcher_role:
await interaction.response.send_message("Server has missing matchy roles :(", ephemeral=True)
return
# Validate that the user has the scope we need
2024-08-08 23:32:52 +01:00
if matcher_role not in interaction.user.roles:
await interaction.response.send_message(f"You'll need the {matcher_role.mention} role to do this, sorry!", ephemeral=True)
2024-08-07 23:23:52 +01:00
return
2024-08-09 14:12:28 +01:00
2024-08-08 23:32:52 +01:00
# Let the channel know the matching is starting
if post:
2024-08-09 00:23:43 +01:00
await interaction.channel.send(f"{interaction.user.display_name} asked me to match groups of {per_group}! :partying_face:")
2024-08-07 23:23:52 +01:00
# Find all the members in the role
2024-08-09 00:06:23 +01:00
matchees = list( m for m in interaction.channel.members if not m.bot and matchee_role in m.roles)
2024-08-08 23:32:52 +01:00
logger.info(f"{len(matchees)} matchees found")
2024-08-07 23:23:52 +01:00
# Shuffle the people for randomness
2024-08-08 23:32:52 +01:00
random.shuffle(matchees)
# Calculate the number of groups to generate
2024-08-08 23:32:52 +01:00
total_num = len(matchees)
2024-08-09 00:06:23 +01:00
num_groups = max(total_num//per_group, 1)
2024-08-08 23:32:52 +01:00
logger.info(f"Creating {num_groups} groups")
# Split members into groups and share them
2024-08-08 23:32:52 +01:00
groups = [matchees[i::num_groups] for i in range(num_groups)]
2024-08-09 00:23:43 +01:00
group_msgs = []
for idx, group in enumerate(groups):
2024-08-09 14:12:28 +01:00
mentions = ", ".join([m.mention for m in group])
2024-08-08 23:32:52 +01:00
logger.info(f"Sending group: {list(m.name for m in group)}")
2024-08-09 14:12:28 +01:00
group_msgs.append(f"Matched up {mentions}!")
2024-08-09 00:23:43 +01:00
# Send the messages
if post:
2024-08-09 00:23:43 +01:00
for msg in group_msgs:
await interaction.channel.send(msg)
else:
await interaction.response.send_message("\n".join(group_msgs), ephemeral=True, silent=True)
2024-08-09 14:12:28 +01:00
2024-08-08 23:32:52 +01:00
logger.info(f"Done")
if post:
await interaction.response.send_message("Done :)", ephemeral=True, silent=True)
2024-08-07 23:23:52 +01:00
2024-08-09 00:06:23 +01:00
# Kick off the bot run cycle
handler = logging.StreamHandler()
2024-08-08 23:32:52 +01:00
bot.run(config.TOKEN, log_handler=handler, root_logger=True)