import discord from discord.ext import commands from discord import app_commands import os from dotenv import load_dotenv import asyncio import json # Load environment variables from .env file load_dotenv() TOKEN = os.getenv('DISCORD_TOKEN') # Define your bot intents = discord.Intents.default() intents.members = True # Ensure the bot has permission to read member statuses intents.message_content = True # Ensure the bot can read message content bot = commands.Bot(command_prefix='/', intents=intents) # File to store the LFM logs log_file = "lfm_logs.json" # Function to load dungeon aliases from a JSON file def load_dungeon_aliases(): with open('dungeon_aliases.json', 'r') as f: return json.load(f) # Load dungeon aliases from the JSON file dungeon_aliases = load_dungeon_aliases() # Reverse the dictionary for easier lookup dungeon_lookup = {} for full_name, aliases in dungeon_aliases.items(): for alias in aliases: dungeon_lookup[alias.lower()] = full_name # Load or create the JSON log file def load_lfm_logs(): if not os.path.exists(log_file): with open(log_file, 'w') as file: json.dump({}, file) # Create an empty JSON structure with open(log_file, 'r') as file: return json.load(file) def save_lfm_logs(logs): with open(log_file, 'w') as file: json.dump(logs, file, indent=4) @bot.event async def on_ready(): print(f'Logged in as {bot.user}') try: synced = await bot.tree.sync() print(f"Synced {len(synced)} commands.") except Exception as e: print(f"Error syncing commands: {e}") @bot.tree.command(name="lfm", description="Start looking for members for a Mythic+ run.") @app_commands.describe( type="Are you wanting to push? Or clear?", dungeon="Name of the dungeon", level="Keystone level" ) @app_commands.choices(type=[ app_commands.Choice(name="Pushing", value="pushing"), app_commands.Choice(name="Completion", value="completion") ]) async def lfm(interaction: discord.Interaction, type: str, dungeon: str, level: int): # The ID of the allowed channel allowed_channel_id = 1297217492699320462 # Replace this with the correct channel ID # Fetch the allowed channel by ID and resolve its name allowed_channel = bot.get_channel(allowed_channel_id) if interaction.channel.id != allowed_channel_id: await interaction.response.send_message( f"This command can only be used in **#{allowed_channel.name}**.", ephemeral=True ) return # Exit the command if the channel ID does not match if type not in ['pushing', 'completion']: await interaction.response.send_message("Please specify the type as either 'pushing' or 'completion'.", ephemeral=True) return # Correct the dungeon name using the alias lookup dungeon_lower = dungeon.lower() full_dungeon_name = dungeon_lookup.get(dungeon_lower) # Fail if the dungeon name is invalid if full_dungeon_name is None: await interaction.response.send_message( f"**'{dungeon}'** is not a recognized dungeon name. Please try again with a valid dungeon name or an alias.", ephemeral=True ) return # Exit the command # Send an initial response to acknowledge the command await interaction.response.send_message("Creating your group... Please wait.", ephemeral=True) try: # Create a message for the channel thread_name = f"{full_dungeon_name} - +{level} - {type.capitalize()}" # Create the thread thread = await interaction.channel.create_thread(name=thread_name, message=interaction.message,type=discord.ChannelType.public_thread) # Tag the user in the message user_mention = interaction.user.mention # This will mention the user thread_link = f"[Join the thread here]({thread.jump_url})" # Create the embed embed = discord.Embed(title="Looking for Members!", color=discord.Color.blue()) embed.add_field(name="Dungeon", value=full_dungeon_name, inline=False) embed.add_field(name="Keystone Level", value=f"+{level}", inline=False) embed.add_field(name="Type", value=type.capitalize(), inline=False) embed.add_field(name="Join the Thread", value=thread_link, inline=False) embed.set_footer(text=f"Created by {interaction.user.display_name}", icon_url=interaction.user.avatar.url) # Send the embed to the original channel message = await interaction.channel.send(f"@here", embed=embed) # Log message ID and thread ID logs = load_lfm_logs() logs[str(message.id)] = {"thread_id": thread.id, "status": "active"} save_lfm_logs(logs) # Post a welcome message in the new thread welcome_message = ( f"Welcome to **{full_dungeon_name}**! 🎉\n" "Don't forget to use `/end` when you're done to lock the thread!" ) await thread.send(welcome_message) except discord.Forbidden: await interaction.followup.send("I don't have permission to create a thread in this channel.") except Exception as e: await interaction.followup.send(f"An error occurred: {e}") @bot.tree.command(name="end", description="End the current Mythic+ run.") async def end(interaction: discord.Interaction): # Check if the command is executed within a thread if interaction.channel.type in (discord.ChannelType.public_thread, discord.ChannelType.private_thread): # Lock the thread await interaction.channel.edit(locked=True) # Load the logs and find the corresponding message logs = load_lfm_logs() thread_message_id = None for message_id, info in logs.items(): if info.get("thread_id") == interaction.channel.id: thread_message_id = int(message_id) break if thread_message_id: # Retrieve the original message try: original_message = await interaction.channel.parent.fetch_message(thread_message_id) if original_message: # Edit the original message to indicate the run has ended embed = original_message.embeds[0] # Update the field that says "Join the thread here" embed.set_field_at( 3, # The index of the field to replace (Join the Thread field is the 4th, so index is 3) name="Status", value="This run has now ended", # Replace "Join the thread here" with this message inline=False ) await original_message.edit(embed=embed) # Mark the run as ended in the logs logs[str(thread_message_id)]["status"] = "ended" del logs[str(thread_message_id)] save_lfm_logs(logs) except discord.NotFound: await interaction.response.send_message("Could not find the original message.", ephemeral=True) # Send a message indicating the run has ended await interaction.channel.send("This run has now ended.") await interaction.response.send_message("The run has been successfully ended.", ephemeral=True) else: await interaction.response.send_message("This command can only be used in a thread.", ephemeral=True) # Run the bot bot.run(TOKEN)