Kuby/commandes/welcome.py
2026-02-20 13:44:07 +01:00

243 lines
12 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
from discord import app_commands
import sqlite3
import aiohttp
import io
import os
import logging
from PIL import Image, ImageDraw, ImageFont
kuby_logger = logging.getLogger("KubyBot")
class Welcome(commands.Cog):
def __init__(self, bot):
self.bot = bot
# Base de données à la racine
self.db_path = os.path.join(os.path.dirname(__file__), "..", "config.db")
self._init_db()
def _init_db(self):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS server_configs (
server_id INTEGER PRIMARY KEY,
welcome_channel INTEGER,
goodbye_channel INTEGER,
welcome_dm_message TEXT,
welcome_server_name TEXT,
welcome_banner_background TEXT,
welcome_channel_message TEXT
)
''')
# Migration pour ajouter les colonnes si elles n'existent pas
cursor.execute("PRAGMA table_info(server_configs)")
columns = [col[1] for col in cursor.fetchall()]
if 'welcome_server_name' not in columns:
cursor.execute('ALTER TABLE server_configs ADD COLUMN welcome_server_name TEXT')
if 'welcome_banner_background' not in columns:
cursor.execute('ALTER TABLE server_configs ADD COLUMN welcome_banner_background TEXT')
if 'welcome_channel_message' not in columns:
cursor.execute('ALTER TABLE server_configs ADD COLUMN welcome_channel_message TEXT')
# Migration: Conversion des chemins absolus en chemins relatifs pour les bannières
cursor.execute("SELECT server_id, welcome_banner_background FROM server_configs WHERE welcome_banner_background IS NOT NULL")
for server_id, path in cursor.fetchall():
if path and os.path.isabs(path):
filename = os.path.basename(path)
# Vérifier si c'est bien une bannière dans le dossier banners
if "banner_" in filename:
cursor.execute("UPDATE server_configs SET welcome_banner_background = ? WHERE server_id = ?", (filename, server_id))
conn.commit()
conn.close()
async def create_welcome_image(self, username, avatar_url, server_name=None, banner_background=None):
current_dir = os.path.dirname(__file__)
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
try:
async with aiohttp.ClientSession() as session:
async with session.get(avatar_url) as resp:
avatar_bytes = await resp.read()
# Utiliser le fond personnalisé ou celui par défaut
bg_path = None
if banner_background:
# Si c'est un chemin absolu (pour compatibilité temporaire)
if os.path.isabs(banner_background) and os.path.exists(banner_background):
bg_path = banner_background
else:
# Sinon on cherche dans le dossier banners/
potential_path = os.path.join(base_dir, "banners", banner_background)
if os.path.exists(potential_path):
bg_path = potential_path
if bg_path:
background = Image.open(bg_path)
else:
background = Image.open(os.path.join(base_dir, 'background_template.png'))
draw = ImageDraw.Draw(background)
font_large = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 70)
font_small = ImageFont.truetype(os.path.join(base_dir, 'custom_font_small.otf'), 50)
draw.text((325, 70), "Bienvenue", font=font_large, fill=(255,255,255))
draw.text((325, 135), f"{username}", font=font_small, fill=(255,255,255))
# Afficher le nom du serveur uniquement si configuré
if server_name:
font_server = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 55)
draw.text((325, 195), server_name, font=font_server, fill=(255,255,255))
avatar = Image.open(io.BytesIO(avatar_bytes)).convert("RGBA").resize((224, 224), Image.LANCZOS)
mask = Image.new('L', avatar.size, 0)
mask_draw = ImageDraw.Draw(mask)
mask_draw.ellipse((12, 12, 212, 212), fill=255)
background.paste(avatar, (40, 40), mask)
img_byte_arr = io.BytesIO()
background.save(img_byte_arr, format='PNG')
img_byte_arr.seek(0)
return img_byte_arr
except Exception as e:
logging.error(f"Erreur image: {e}")
return None
@commands.Cog.listener()
async def on_member_join(self, member):
kuby_logger.info(f"📥 [Welcome] Événement on_member_join reçu pour {member.name} (ID: {member.id}) sur {member.guild.name}")
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('SELECT welcome_channel, welcome_dm_message, welcome_server_name, welcome_banner_background, welcome_channel_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
result = cursor.fetchone()
conn.close()
if not result:
kuby_logger.warning(f"⚠️ [Welcome] Aucune configuration trouvée dans la base de données pour le serveur {member.guild.id}")
return
welcome_channel = result[0]
welcome_dm_text = result[1]
server_name = result[2]
banner_background = result[3]
welcome_channel_message = result[4]
kuby_logger.debug(f"🔍 [Welcome] Config récupérée: DM={bool(welcome_dm_text)}, Channel={welcome_channel}")
# 1. Gestion du DM
if welcome_dm_text:
kuby_logger.info(f"✉️ [Welcome] Tentative d'envoi de DM à {member.name}")
try:
formatted_message = welcome_dm_text.format(
username=member.name,
servername=member.guild.name,
member_count=member.guild.member_count
)
await member.send(formatted_message)
await member.send("https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExNXV1NW02NTk0bGF2ZHcyMGFna2F6amRrbGpobGpsMHowOW5xa2E5eCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/ZtFuW4rsUbfrRzPauJ/giphy.gif")
kuby_logger.info(f"✅ [Welcome] DM envoyé avec succès à {member.name}")
except discord.Forbidden:
kuby_logger.warning(f"🚫 [Welcome] Impossible d'envoyer le DM à {member.name} (DMs fermés)")
except Exception as e:
kuby_logger.error(f"❌ [Welcome] Erreur lors de l'envoi du DM à {member.name}: {e}", exc_info=True)
else:
kuby_logger.info(f" [Welcome] Aucun message de DM configuré pour le serveur {member.guild.id}")
except Exception as e:
kuby_logger.error(f"❌ [Welcome] Erreur critique dans on_member_join: {e}", exc_info=True)
# 2. Gestion du salon de bienvenue
if welcome_channel:
channel = member.guild.get_channel(welcome_channel)
if channel:
img = await self.create_welcome_image(
member.name,
member.avatar.url if member.avatar else member.default_avatar.url,
server_name=server_name,
banner_background=banner_background
)
if img:
# Utiliser le message personnalisé ou un message par défaut
channel_description = welcome_channel_message.format(
username=member.name,
servername=member.guild.name,
member_count=member.guild.member_count
) if welcome_channel_message else "Bienvenue dans le serveur !\nSi vous cherchez des RolePlay de qualité,\nVous êtes au bon endroit. <a:sip:1316891821858619452>"
embed = discord.Embed(title=f"Merci d'accueillir {member} 🤝",
description=channel_description,
color=discord.Color.dark_purple())
embed.set_image(url="attachment://welcome.png")
await channel.send(content=member.mention, embed=embed, file=discord.File(img, filename="welcome.png"))
async def save_banner_attachment(self, attachment: discord.Attachment, guild_id: int) -> str:
"""Sauvegarde l'attachment et retourne le chemin du fichier"""
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "banners"))
os.makedirs(base_dir, exist_ok=True)
# Vérifier que c'est une image
if not attachment.content_type or not attachment.content_type.startswith('image/'):
raise ValueError("Le fichier doit être une image.")
# Vérifier le format PNG
if not attachment.filename.lower().endswith('.png'):
raise ValueError("Le fichier doit être au format PNG.")
# Vérifier les dimensions
banner_path = os.path.join(base_dir, f"banner_{guild_id}.png")
async with aiohttp.ClientSession() as session:
async with session.get(attachment.url) as resp:
if resp.status == 200:
# Vérifier les dimensions avant de sauvegarder
img_data = await resp.read()
from io import BytesIO
with Image.open(BytesIO(img_data)) as img:
width, height = img.size
if width != 1000 or height != 300:
raise ValueError(f"Les dimensions doivent être 1000x300 pixels (votre image: {width}x{height})")
with open(banner_path, 'wb') as f:
f.write(img_data)
return os.path.basename(banner_path)
@app_commands.command(name="setwelcome", description="Définit le salon, les messages de bienvenue et le fond de la bannière")
@app_commands.checks.has_permissions(administrator=True)
async def set_welcome(self, interaction: discord.Interaction, channel: discord.TextChannel, message_dm: str, message_salon: str, server_name: str, banner_file: discord.Attachment = None):
banner_path = None
# Si un fichier est uploadé, le sauvegarder
if banner_file:
try:
banner_path = await self.save_banner_attachment(banner_file, interaction.guild_id)
except Exception as e:
await interaction.response.send_message(f"❌ Erreur avec le fichier: {e}", ephemeral=True)
return
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''INSERT INTO server_configs (server_id, welcome_channel, welcome_dm_message, welcome_server_name, welcome_banner_background, welcome_channel_message)
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(server_id)
DO UPDATE SET welcome_channel=excluded.welcome_channel,
welcome_dm_message=excluded.welcome_dm_message,
welcome_server_name=excluded.welcome_server_name,
welcome_banner_background=COALESCE(excluded.welcome_banner_background, welcome_banner_background),
welcome_channel_message=excluded.welcome_channel_message''',
(interaction.guild_id, channel.id, message_dm, server_name, banner_path, message_salon))
conn.commit()
conn.close()
bg_used = "background_template.png" if not banner_path else (banner_path.split('/')[-1])
await interaction.response.send_message(f"✅ Configuration de bienvenida enregistrée !\nFond utilisé: {bg_used}", ephemeral=True)
async def setup(bot):
await bot.add_cog(Welcome(bot))