Mise à jour du système de bienvenue § ajout de plusieurs fonctionnalités de personnalisation (message perso, bannière perso etc...)
This commit is contained in:
parent
44eefeac6c
commit
10173132a2
7 changed files with 221 additions and 51 deletions
BIN
banners/banner_1369669999345537145.png
Normal file
BIN
banners/banner_1369669999345537145.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
1
bot.py
1
bot.py
|
|
@ -51,7 +51,6 @@ class MyBot(commands.Bot):
|
||||||
"commandes.sendbotmessages",
|
"commandes.sendbotmessages",
|
||||||
"commandes.goodbye",
|
"commandes.goodbye",
|
||||||
"commandes.welcome",
|
"commandes.welcome",
|
||||||
"commandes.fun",
|
|
||||||
"commandes.security",
|
"commandes.security",
|
||||||
"commandes.snipe",
|
"commandes.snipe",
|
||||||
"commandes.scan",
|
"commandes.scan",
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import discord
|
|
||||||
from discord import app_commands
|
|
||||||
from discord.ext import commands
|
|
||||||
import random
|
|
||||||
|
|
||||||
class FunCommands(commands.Cog):
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.emojis = ['😀', '😂', '😎', '😍', '😡', '🤖', '👻', '🎉', '🔥', '🌈', '🍕', '🍔', '🍟', '🚀', '🌟']
|
|
||||||
|
|
||||||
@app_commands.command(name="fun", description="Envoie 10 emojis fun aléatoires")
|
|
||||||
async def fun(self, interaction: discord.Interaction):
|
|
||||||
chosen_emojis = random.sample(self.emojis, 10)
|
|
||||||
await interaction.response.send_message(" ".join(chosen_emojis))
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(FunCommands(bot))
|
|
||||||
|
|
@ -23,13 +23,29 @@ class Welcome(commands.Cog):
|
||||||
server_id INTEGER PRIMARY KEY,
|
server_id INTEGER PRIMARY KEY,
|
||||||
welcome_channel INTEGER,
|
welcome_channel INTEGER,
|
||||||
goodbye_channel INTEGER,
|
goodbye_channel INTEGER,
|
||||||
welcome_dm_message TEXT
|
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.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
async def create_welcome_image(self, username, avatar_url):
|
async def create_welcome_image(self, username, avatar_url, server_name=None, banner_background=None):
|
||||||
current_dir = os.path.dirname(__file__)
|
current_dir = os.path.dirname(__file__)
|
||||||
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
base_dir = os.path.abspath(os.path.join(current_dir, ".."))
|
||||||
|
|
||||||
|
|
@ -38,16 +54,24 @@ class Welcome(commands.Cog):
|
||||||
async with session.get(avatar_url) as resp:
|
async with session.get(avatar_url) as resp:
|
||||||
avatar_bytes = await resp.read()
|
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'))
|
background = Image.open(os.path.join(base_dir, 'background_template.png'))
|
||||||
|
|
||||||
draw = ImageDraw.Draw(background)
|
draw = ImageDraw.Draw(background)
|
||||||
|
|
||||||
font_large = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 70)
|
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)
|
font_small = ImageFont.truetype(os.path.join(base_dir, 'custom_font_small.otf'), 50)
|
||||||
font_large_omega = ImageFont.truetype(os.path.join(base_dir, 'custom_font_large.otf'), 55)
|
|
||||||
|
|
||||||
draw.text((325, 70), "Bienvenue", font=font_large, fill=(255,255,255))
|
draw.text((325, 70), "Bienvenue", font=font_large, fill=(255,255,255))
|
||||||
draw.text((325, 135), f"{username} chez", font=font_small, fill=(255,255,255))
|
draw.text((325, 135), f"{username}", font=font_small, fill=(255,255,255))
|
||||||
draw.text((325, 195), "OMEGA KUBE", font=font_large_omega, 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)
|
avatar = Image.open(io.BytesIO(avatar_bytes)).convert("RGBA").resize((224, 224), Image.LANCZOS)
|
||||||
mask = Image.new('L', avatar.size, 0)
|
mask = Image.new('L', avatar.size, 0)
|
||||||
|
|
@ -67,14 +91,18 @@ class Welcome(commands.Cog):
|
||||||
async def on_member_join(self, member):
|
async def on_member_join(self, member):
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# On récupère 2 colonnes : index 0 et 1
|
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,))
|
||||||
cursor.execute('SELECT welcome_channel, welcome_dm_message FROM server_configs WHERE server_id = ?', (member.guild.id,))
|
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# 1. Gestion du DM (Index 1)
|
welcome_channel = result[0] if result else None
|
||||||
welcome_dm_text = result[1] if result and result[1] else "Bienvenue {username} sur le serveur {servername} ! 🎉\n\nNous sommes ravis de t'accueillir parmi nous."
|
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:
|
try:
|
||||||
formatted_message = welcome_dm_text.format(
|
formatted_message = welcome_dm_text.format(
|
||||||
username=member.name,
|
username=member.name,
|
||||||
|
|
@ -86,31 +114,91 @@ class Welcome(commands.Cog):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning(f"Impossible d'envoyer le DM à {member.name}: {e}")
|
logging.warning(f"Impossible d'envoyer le DM à {member.name}: {e}")
|
||||||
|
|
||||||
# 2. Gestion du salon de bienvenue (Index 0)
|
# 2. Gestion du salon de bienvenue
|
||||||
if result and result[0]:
|
if welcome_channel:
|
||||||
channel = member.guild.get_channel(result[0])
|
channel = member.guild.get_channel(welcome_channel)
|
||||||
if channel:
|
if channel:
|
||||||
img = await self.create_welcome_image(member.name, member.avatar.url if member.avatar else member.default_avatar.url)
|
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:
|
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} 🤝",
|
embed = discord.Embed(title=f"Merci d'accueillir {member} 🤝",
|
||||||
description="Bienvenue dans le serveur Omega Kube !\nSi vous cherchez des RolePlay de qualité,\nVous êtes au bon endroit. <a:sip:1316891821858619452>",
|
description=channel_description,
|
||||||
color=discord.Color.dark_purple())
|
color=discord.Color.dark_purple())
|
||||||
embed.set_image(url="attachment://welcome.png")
|
embed.set_image(url="attachment://welcome.png")
|
||||||
await channel.send(content=member.mention, embed=embed, file=discord.File(img, filename="welcome.png"))
|
await channel.send(content=member.mention, embed=embed, file=discord.File(img, filename="welcome.png"))
|
||||||
|
|
||||||
@app_commands.command(name="setwelcome", description="Définit le salon et le message DM de bienvenue")
|
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)
|
@app_commands.checks.has_permissions(administrator=True)
|
||||||
async def set_welcome(self, interaction: discord.Interaction, channel: discord.TextChannel, message_dm: str = None):
|
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)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute('''INSERT INTO server_configs (server_id, welcome_channel, welcome_dm_message)
|
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)
|
VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(server_id)
|
||||||
DO UPDATE SET welcome_channel=excluded.welcome_channel,
|
DO UPDATE SET welcome_channel=excluded.welcome_channel,
|
||||||
welcome_dm_message=COALESCE(excluded.welcome_dm_message, welcome_dm_message)''',
|
welcome_dm_message=excluded.welcome_dm_message,
|
||||||
(interaction.guild_id, channel.id, message_dm))
|
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.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
await interaction.response.send_message("Configuration de bienvenue enregistrée !", ephemeral=True)
|
|
||||||
|
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):
|
async def setup(bot):
|
||||||
await bot.add_cog(Welcome(bot))
|
await bot.add_cog(Welcome(bot))
|
||||||
|
|
||||||
|
|
|
||||||
BIN
config.db
BIN
config.db
Binary file not shown.
58
data/logs/member_events_2026-01-03.json
Normal file
58
data/logs/member_events_2026-01-03.json
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:25:17.730927",
|
||||||
|
"event_type": "member_leave",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null,
|
||||||
|
"roles": {
|
||||||
|
"role_ids": [
|
||||||
|
1369669999366770721
|
||||||
|
],
|
||||||
|
"role_names": [
|
||||||
|
"Faux banquier"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
8192
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"joined_at": "2026-01-01T21:00:26.074000+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:25:28.894683",
|
||||||
|
"event_type": "member_join",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:49:33.975462",
|
||||||
|
"event_type": "member_leave",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null,
|
||||||
|
"roles": {
|
||||||
|
"role_ids": [
|
||||||
|
1369669999366770721
|
||||||
|
],
|
||||||
|
"role_names": [
|
||||||
|
"Faux banquier"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
8192
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"joined_at": "2026-01-03T20:25:28.737000+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:49:55.375389",
|
||||||
|
"event_type": "member_join",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null
|
||||||
|
}
|
||||||
|
]
|
||||||
42
data/member_logs/1456390746167967932.json
Normal file
42
data/member_logs/1456390746167967932.json
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:25:17.730927",
|
||||||
|
"event_type": "member_leave",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null,
|
||||||
|
"roles": {
|
||||||
|
"role_ids": [
|
||||||
|
1369669999366770721
|
||||||
|
],
|
||||||
|
"role_names": [
|
||||||
|
"Faux banquier"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
8192
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"joined_at": "2026-01-01T21:00:26.074000+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-01-03T21:49:33.975462",
|
||||||
|
"event_type": "member_leave",
|
||||||
|
"member_id": 1456390746167967932,
|
||||||
|
"member_name": "juibu_66388",
|
||||||
|
"member_discriminator": "0",
|
||||||
|
"member_avatar": null,
|
||||||
|
"roles": {
|
||||||
|
"role_ids": [
|
||||||
|
1369669999366770721
|
||||||
|
],
|
||||||
|
"role_names": [
|
||||||
|
"Faux banquier"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
8192
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"joined_at": "2026-01-03T20:25:28.737000+00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue