diff --git a/addonsearch.py b/addonsearch.py index eb03eb0..0aca1b9 100644 --- a/addonsearch.py +++ b/addonsearch.py @@ -1,31 +1,31 @@ import discord import meilisearch -import json import dotenv import os + dotenv.load_dotenv() client = meilisearch.Client(os.getenv("SEARCH-URL"), os.getenv("SEARCH-TOKEN")) loaders = ["Forge", "NeoForge", "Fabric", "Quilt"] index = client.index("addons") -async def addonsearch(ctx, query, limit=1): +async def addonsearch(interaction: discord.Interaction, query: str, limit: int = 1): request = index.search(query, {"limit": limit}) - data = request.get("hits", []) # Safely get 'hits' (default to empty list if not found) - await send_embeds(ctx, data) + data = request.get("hits", []) # Récupérer en toute sécurité 'hits' ou une liste vide + await send_embeds(interaction, data) return data -async def send_embeds(message, data): - for mod_data in data: # `data` is a list of addon dictionaries +async def send_embeds(interaction: discord.Interaction, data: list[dict]): + for mod_data in data: # `data` est une liste de dictionnaires d'addons embed = await gen_embed(mod_data) - await message.reply(embed=embed) + await interaction.followup.send(embed=embed) -def format_loaders(loaders): +def format_loaders(loaders: list[str]) -> str: if not loaders: return "No loaders available" return " ".join([f"{loader}" for loader in loaders]) -async def gen_embed(data): - loaders_field = format_loaders(data.get("loaders", [])) # Use `.get()` for safety +async def gen_embed(data: dict) -> discord.Embed: + loaders_field = format_loaders(data.get("loaders", [])) embed = discord.Embed(title=data["name"], description=data["description"], color=0x689AEE) embed.set_author(name=data["author"]) embed.set_thumbnail(url=data["icon"]) diff --git a/bot.py b/bot.py index 2e12217..d5d1272 100644 --- a/bot.py +++ b/bot.py @@ -1,24 +1,29 @@ import discord +from discord import app_commands from discord.ext import commands from colorama import Back, Style from addonsearch import addonsearch from schematicsearch import schematicsearch import dotenv import os + dotenv.load_dotenv() intents = discord.Intents.default() -intents.message_content = True # Required for reading user messages +intents.message_content = True bot = commands.Bot(command_prefix="??", intents=intents) +# Remove the old help command bot.remove_command("help") @bot.event async def on_ready(): + # Synchronize slash commands with Discord + await bot.tree.sync() print(f"{Back.GREEN}Logged in as {bot.user}{Style.RESET_ALL}") -@bot.command() -async def help(ctx): +@bot.tree.command(name="help", description="Displays the list of available commands") +async def help_command(interaction: discord.Interaction): embed = discord.Embed( title="Commands available", description="Addons & Schematics commands", @@ -26,12 +31,12 @@ async def help(ctx): ) embed.add_field( name="Addon Commands", - value="??addon search [how many default=1] - Search for addons on Blueprint.", + value="/addon search [limit=1] - Search for addons on Blueprint.", inline=False ) embed.add_field( name="Schematic Commands", - value="??schematic search [how many default=1]", + value="/schematic search [limit=1]", inline=False ) embed.add_field( @@ -39,57 +44,61 @@ async def help(ctx): value=""" <> - needed [] - optional -""", + """, inline=False ) - await ctx.reply(embed=embed) - -# Create "addon" group command -@bot.group(invoke_without_command=True) -async def addon(ctx): - await ctx.send("Use `??addon search ` to find addons.") - -@bot.group(invoke_without_command=True) -async def schematic(ctx): - await ctx.send("Use `??schematic search ` to find schematics.") + await interaction.response.send_message(embed=embed) -# Subcommand for "addon" -@addon.command() -async def search(ctx, *, query: str): - # Extract the number of results from the end of the query (if available) - parts = query.split() - if parts[-1].isdigit(): - limit = int(parts[-1]) - query = " ".join(parts[:-1]) # Remove the number from the query - else: - limit = 1 # Default to 1 result if no number is specified - - # Ensure the limit is between 1 and 5 +# Slash command for addon search +@bot.tree.command(name="addon", description="Manages commands related to addons") +async def addon_command(interaction: discord.Interaction, query: str, limit: int = 1): limit = max(1, min(limit, 5)) - msg = await ctx.send(f"Searching for {limit} addon(s) related to: `{query}`") - await msg.delete(delay=3) + # Defer the response to avoid InteractionResponded error + await interaction.response.defer(ephemeral=True) + + # Search for addons + await addonsearch(interaction=interaction, query=query, limit=limit) - await addonsearch(ctx=ctx, query=query, limit=limit) +# Slash command for schematic search +@bot.tree.command(name="schematic", description="Manages commands related to schematics") +async def schematic_command(interaction: discord.Interaction, query: str, limit: int = 1): + limit = max(1, min(limit, 5)) + + # Defer the response to avoid InteractionResponded error + await interaction.response.defer(ephemeral=True) + + # Search for schematics + await schematicsearch(interaction=interaction, query=query, limit=limit) -# Subcommand for "schematic" -@schematic.command() -async def search(ctx, *, query: str): - # Extract the number of results from the end of the query (if available) - parts = query.split() - if parts[-1].isdigit(): - limit = int(parts[-1]) - query = " ".join(parts[:-1]) # Remove the number from the query - else: - limit = 1 # Default to 1 result if no number is specified +@bot.tree.command(name="link", description="Displays the link to the official website") +async def site_command(interaction: discord.Interaction): + embed = discord.Embed( + title="Official Website", + description="Visit our website to discover more addons and schematics!", + color=discord.Color.blue(), + url="https://your-website.com" # Replace with your actual URL + ) - # Ensure the limit is between 1 and 5 - limit = max(1, min(limit, 5)) + # Add an image to the embed (optional) + embed.set_thumbnail(url="https://your-website.com/logo.png") # Replace with your logo URL + + # Add additional information + embed.add_field( + name="Latest Updates", + value="Check out the latest addons and schematics added to our site!", + inline=False + ) + + embed.add_field( + name="Support", + value="Need help? Visit our forum or contact us directly on the site.", + inline=False + ) - msg = await ctx.send(f"Searching for {limit} schematic(s) related to: `{query}`") - await msg.delete(delay=3) + # Add a footer + embed.set_footer(text="© 2025 Your Name - All rights reserved") - # Fetch data - await schematicsearch(ctx=ctx, query=query, limit=limit) + await interaction.response.send_message(embed=embed) bot.run(os.getenv("TOKEN")) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5eaaab7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +discord.py +colorama +python-dotenv +meilisearch \ No newline at end of file diff --git a/schematicsearch.py b/schematicsearch.py index 5966a95..61b1588 100644 --- a/schematicsearch.py +++ b/schematicsearch.py @@ -1,22 +1,23 @@ -import discord import meilisearch -import json -import dotenv +import discord import os -dotenv.load_dotenv() + +# Charger la configuration de Meilisearch depuis les variables d'environnement client = meilisearch.Client(os.getenv("SEARCH-URL"), os.getenv("SEARCH-TOKEN")) -loaders = ["forge", "neoforge", "fabric", "quilt"] index = client.index("schematics") -async def schematicsearch(ctx, query, limit=1): +async def schematicsearch(interaction: discord.Interaction, query: str, limit: int = 1): + # Effectuer la recherche dans Meilisearch request = index.search(query, {"limit": limit}) - data = request.get("hits", []) # Safely get 'hits' (default to empty list if not found) - await send_embeds(ctx.message, data) + data = request.get("hits", []) + + # Envoyer la réponse sous forme d'embed + await send_embeds(interaction, data) -async def send_embeds(message, data): - for mod_data in data: # `data` is a list of addon dictionaries +async def send_embeds(interaction: discord.Interaction, data): + for mod_data in data: embed = await gen_embed(mod_data) - await message.reply(embed=embed) + await interaction.followup.send(embed=embed) # Utiliser followup.send() après defer() def format_loaders(loaders): if not loaders: @@ -24,14 +25,11 @@ def format_loaders(loaders): return " ".join([f"{loader}" for loader in loaders]) async def gen_embed(data): - loaders_field = format_loaders(data.get("modloaders", [])) # Use `.get()` for safety + loaders_field = format_loaders(data.get("modloaders", [])) embed = discord.Embed(title=data["title"], description=data["description"], color=0x689AEE) - embed.set_author(name=data["authors"][0]) - embed.set_thumbnail(url=data["image_url"]) + embed.set_author(name=data["$id"]) + embed.set_thumbnail(url=data.get("image_urls", [None])[0]) embed.add_field(name="Loaders", value=loaders_field, inline=False) embed.add_field(name="Download", value=f"https://nottelling.youthe.schematic/schematics/{data['slug']}", inline=False) - embed.add_field(name="Author", value=f"Author: {data['authors'][0]}") embed.set_footer(text=f"Downloads: {data['downloads']}") return embed - -