Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions addonsearch.py
Original file line number Diff line number Diff line change
@@ -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"])
Expand Down
103 changes: 56 additions & 47 deletions bot.py
Original file line number Diff line number Diff line change
@@ -1,95 +1,104 @@
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",
color=discord.Color.blurple()
)
embed.add_field(
name="Addon Commands",
value="??addon search <query> [how many default=1] - Search for addons on Blueprint.",
value="/addon search <query> [limit=1] - Search for addons on Blueprint.",
inline=False
)
embed.add_field(
name="Schematic Commands",
value="??schematic search <query> [how many default=1]",
value="/schematic search <query> [limit=1]",
inline=False
)
embed.add_field(
name="Data types",
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 <query>` to find addons.")

@bot.group(invoke_without_command=True)
async def schematic(ctx):
await ctx.send("Use `??schematic search <query>` 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"))
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
discord.py
colorama
python-dotenv
meilisearch
32 changes: 15 additions & 17 deletions schematicsearch.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
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:
return "No loaders available"
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