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 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') 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 if banner_background and os.path.exists(banner_background): background = Image.open(banner_background) 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): 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() welcome_channel = result[0] if result else None welcome_dm_text = result[1] if result and result[1] else None server_name = result[2] if result and result[2] else None banner_background = result[3] if result and result[3] else None welcome_channel_message = result[4] if result and result[4] else None # 1. Gestion du DM if welcome_dm_text: 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") except Exception as e: logging.warning(f"Impossible d'envoyer le DM à {member.name}: {e}") # 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. " 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 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))