Files
epicthefamily/bot.py
2025-04-20 00:29:58 +02:00

245 lines
7.9 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import discord
from discord.ext import commands
import json
import aiohttp
import os
from dotenv import load_dotenv
from family import FamilyManager
from tree import generate_tree
from typing import Optional
# Configuration initiale
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
with open("config.json") as f:
config = json.load(f)
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
family = FamilyManager("family.json")
async def download_avatar(member: discord.Member) -> Optional[str]:
"""Télécharge et enregistre l'avatar d'un membre"""
if not member.avatar:
return None
avatar_dir = "avatars"
os.makedirs(avatar_dir, exist_ok=True)
avatar_path = f"{avatar_dir}/{member.id}.png"
try:
async with aiohttp.ClientSession() as session:
async with session.get(str(member.avatar.url)) as resp:
if resp.status == 200:
with open(avatar_path, "wb") as f:
f.write(await resp.read())
return avatar_path
except Exception as e:
print(f"Erreur de téléchargement avatar {member.id}: {e}")
return None
async def update_member(member: discord.Member):
"""Met à jour les infos d'un membre dans la famille"""
avatar_url = str(member.avatar.url) if member.avatar else None
family.add_member(
str(member.id),
member.display_name,
avatar_url
)
await download_avatar(member)
@bot.event
async def on_ready():
print(f"Connecté en tant que {bot.user} (ID: {bot.user.id})")
try:
synced = await bot.tree.sync()
print(f"Commandes synchronisées ({len(synced)}): {[c.name for c in synced]}")
except Exception as e:
print(f"Erreur synchronisation commandes: {e}")
@bot.tree.command(name="enregistrer", description="Enregistre ou met à jour son profil")
async def enregistrer(interaction: discord.Interaction):
"""Commande pour que les membres enregistrent leurs infos"""
await update_member(interaction.user)
await interaction.response.send_message(
"✅ Profil mis à jour avec succès !",
ephemeral=True
)
@bot.tree.command(name="adopter", description="Adopter un membre")
async def adopter(interaction: discord.Interaction, enfant: discord.Member):
parent = interaction.user
# Validations
if parent.id == enfant.id:
await interaction.response.send_message("❌ Auto-adoption impossible !", ephemeral=True)
return
if family.get_generation(str(enfant.id)) < family.get_generation(str(parent.id)):
await interaction.response.send_message(
"❌ Structure familiale invalide !",
ephemeral=True
)
return
# Met à jour les infos des membres
await update_member(parent)
await update_member(enfant)
# Crée le lien familial
if not family.add_child(str(parent.id), str(enfant.id)):
await interaction.response.send_message(
"❌ Erreur lors de l'adoption",
ephemeral=True
)
return
# Attribue le rôle approprié
generation = family.get_generation(str(enfant.id))
role_id = config["ROLE_IDS"].get(
"ENFANT" if generation == 1 else
"PETIT_ENFANT" if generation == 2 else
"ARRIERE_PETIT_ENFANT"
)
role = interaction.guild.get_role(role_id)
if role:
try:
await enfant.add_roles(role)
message = f"{parent.mention} a adopté {enfant.mention} !"
# Mentionne le partenaire si existe
partner_id = family.get_partner(str(parent.id))
if partner_id:
partner = interaction.guild.get_member(int(partner_id))
if partner:
message += f"\n👫 Partenaire : {partner.mention}"
await interaction.response.send_message(message)
except discord.Forbidden:
await interaction.response.send_message(
"❌ Permission refusée pour attribuer le rôle !",
ephemeral=True
)
else:
await interaction.response.send_message(
"❌ Rôle introuvable ! Contactez un administrateur.",
ephemeral=True
)
@bot.tree.command(name="couple", description="Officialiser une relation")
async def couple(interaction: discord.Interaction, partenaire: discord.Member):
membre = interaction.user
# Validations
if membre.id == partenaire.id:
await interaction.response.send_message(
"❌ Impossible de former un couple avec soi-même !",
ephemeral=True
)
return
# Met à jour les infos
await update_member(membre)
await update_member(partenaire)
if family.add_couple(str(membre.id), str(partenaire.id)):
await interaction.response.send_message(
f"💑 {membre.mention} et {partenaire.mention} sont maintenant partenaires !"
)
else:
await interaction.response.send_message(
"❌ Ces membres sont déjà en couple !",
ephemeral=True
)
@bot.tree.command(name="renier", description="Renier un enfant")
async def renier(interaction: discord.Interaction, enfant: discord.Member):
parent = interaction.user
success = family.remove_child(str(parent.id), str(enfant.id))
if success:
# Retire le rôle
generation = family.get_generation(str(enfant.id))
role_id = config["ROLE_IDS"].get(
"ENFANT" if generation == 1 else
"PETIT_ENFANT" if generation == 2 else
"ARRIERE_PETIT_ENFANT"
)
if role_id:
role = interaction.guild.get_role(role_id)
if role:
try:
await enfant.remove_roles(role)
except discord.Forbidden:
pass # On continue même si échec du retrait de rôle
await interaction.response.send_message(
f"{parent.mention} a renié {enfant.mention} !"
)
else:
await interaction.response.send_message(
"❌ Aucun lien parental trouvé.",
ephemeral=True
)
@bot.tree.command(name="arbre", description="Afficher l'arbre généalogique")
async def arbre(interaction: discord.Interaction):
await interaction.response.defer()
# Télécharge les avatars des membres
members = family.get_all_members()
for member_id in members:
try:
member = await interaction.guild.fetch_member(int(member_id))
await download_avatar(member)
except:
continue
# Génère l'arbre
generate_tree("family.json", "arbre.png", config["ROOT_MEMBER_ID"])
# Envoie le résultat
try:
await interaction.followup.send(file=discord.File("arbre.png"))
except:
await interaction.followup.send(
"❌ Erreur lors de la génération de l'arbre",
ephemeral=True
)
@bot.tree.command(name="parent", description="Voir les parents d'un membre")
async def parent(interaction: discord.Interaction, membre: Optional[discord.Member] = None):
target = membre or interaction.user
parents = family.get_parents(str(target.id))
if not parents:
await interaction.response.send_message(
f" {target.display_name} n'a pas de parent enregistré.",
ephemeral=True
)
return
parent_mentions = [f"<@{p['id']}>" for p in parents]
await interaction.response.send_message(
f"👪 Parents de {target.mention} : {' '.join(parent_mentions)}"
)
@bot.command()
@commands.has_permissions(administrator=True)
async def init(ctx):
"""Initialise tous les membres du serveur (admin seulement)"""
count = 0
for member in ctx.guild.members:
await update_member(member)
count += 1
await ctx.send(f"{count} membres initialisés !")
bot.run(TOKEN)