mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-07 23:04:36 +02:00
feat: Enhance goodbye and welcome forms with new message types and image options
- Added support for different message types (text, embed, both) in goodbye and welcome forms. - Implemented embed options including title, description, color, thumbnail, and footer for both forms. - Introduced image options with gradient selection, title, subtitle, and member count display for goodbye and welcome messages. - Updated API routes to handle new configuration parameters for saving and retrieving goodbye and welcome settings. - Created a new function to generate welcome images with customizable gradients and text.
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
const { createCanvas, loadImage, registerFont } = require('canvas');
|
||||
const path = require('path');
|
||||
|
||||
// Couleurs par défaut pour les dégradés
|
||||
const GRADIENTS = {
|
||||
purple: ['#667eea', '#764ba2'],
|
||||
blue: ['#4facfe', '#00f2fe'],
|
||||
green: ['#11998e', '#38ef7d'],
|
||||
red: ['#ff416c', '#ff4b2b'],
|
||||
orange: ['#f12711', '#f5af19'],
|
||||
pink: ['#ee0979', '#ff6a00'],
|
||||
dark: ['#232526', '#414345'],
|
||||
sunset: ['#fa709a', '#fee140'],
|
||||
ocean: ['#2193b0', '#6dd5ed'],
|
||||
forest: ['#134e5e', '#71b280']
|
||||
};
|
||||
|
||||
/**
|
||||
* Génère une image de bienvenue/au revoir
|
||||
* @param {Object} options - Options de génération
|
||||
* @param {string} options.type - 'welcome' ou 'goodbye'
|
||||
* @param {string} options.username - Nom d'utilisateur
|
||||
* @param {string} options.discriminator - Discriminateur (ou pseudo global)
|
||||
* @param {string} options.avatarURL - URL de l'avatar
|
||||
* @param {string} options.serverName - Nom du serveur
|
||||
* @param {string} options.memberCount - Nombre de membres (optionnel)
|
||||
* @param {string} options.gradient - Nom du dégradé ou couleurs custom
|
||||
* @param {string} options.title - Titre personnalisé (optionnel)
|
||||
* @param {string} options.subtitle - Sous-titre personnalisé (optionnel)
|
||||
* @returns {Promise<Buffer>} - Buffer de l'image PNG
|
||||
*/
|
||||
async function generateWelcomeImage(options) {
|
||||
const {
|
||||
type = 'welcome',
|
||||
username,
|
||||
discriminator = '',
|
||||
avatarURL,
|
||||
serverName,
|
||||
memberCount = null,
|
||||
gradient = 'purple',
|
||||
title = null,
|
||||
subtitle = null
|
||||
} = options;
|
||||
|
||||
// Dimensions de l'image
|
||||
const width = 800;
|
||||
const height = 250;
|
||||
|
||||
const canvas = createCanvas(width, height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Créer le dégradé de fond
|
||||
let colors = GRADIENTS[gradient] || GRADIENTS.purple;
|
||||
if (Array.isArray(gradient) && gradient.length >= 2) {
|
||||
colors = gradient;
|
||||
}
|
||||
|
||||
const grd = ctx.createLinearGradient(0, 0, width, height);
|
||||
grd.addColorStop(0, colors[0]);
|
||||
grd.addColorStop(1, colors[1]);
|
||||
|
||||
// Fond avec coins arrondis
|
||||
roundRect(ctx, 0, 0, width, height, 20);
|
||||
ctx.fillStyle = grd;
|
||||
ctx.fill();
|
||||
|
||||
// Ajouter un effet de vague/pattern subtil
|
||||
ctx.globalAlpha = 0.1;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, height - 50 + i * 20);
|
||||
ctx.quadraticCurveTo(width / 4, height - 80 + i * 20, width / 2, height - 50 + i * 20);
|
||||
ctx.quadraticCurveTo(width * 3 / 4, height - 20 + i * 20, width, height - 50 + i * 20);
|
||||
ctx.lineTo(width, height);
|
||||
ctx.lineTo(0, height);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
// Charger et dessiner l'avatar avec bordure circulaire
|
||||
try {
|
||||
const avatar = await loadImage(avatarURL);
|
||||
const avatarSize = 130;
|
||||
const avatarX = 50;
|
||||
const avatarY = (height - avatarSize) / 2;
|
||||
|
||||
// Ombre de l'avatar
|
||||
ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.shadowOffsetX = 0;
|
||||
ctx.shadowOffsetY = 5;
|
||||
|
||||
// Bordure blanche de l'avatar
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2 + 5, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fill();
|
||||
|
||||
ctx.shadowColor = 'transparent';
|
||||
ctx.shadowBlur = 0;
|
||||
|
||||
// Dessiner l'avatar en cercle
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.closePath();
|
||||
ctx.clip();
|
||||
ctx.drawImage(avatar, avatarX, avatarY, avatarSize, avatarSize);
|
||||
ctx.restore();
|
||||
|
||||
} catch (err) {
|
||||
// Si l'avatar ne charge pas, dessiner un cercle par défaut
|
||||
const avatarSize = 130;
|
||||
const avatarX = 50;
|
||||
const avatarY = (height - avatarSize) / 2;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Zone de texte
|
||||
const textX = 210;
|
||||
|
||||
// Titre principal (Bienvenue / Au revoir)
|
||||
const defaultTitle = type === 'welcome' ? 'Bienvenue' : 'Au revoir';
|
||||
const displayTitle = title || defaultTitle;
|
||||
|
||||
ctx.font = 'bold 42px Arial, sans-serif';
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
|
||||
ctx.shadowBlur = 5;
|
||||
ctx.shadowOffsetX = 2;
|
||||
ctx.shadowOffsetY = 2;
|
||||
ctx.fillText(displayTitle, textX, 75);
|
||||
|
||||
// Sous-titre (sur le serveur Discord / a quitté le serveur)
|
||||
const defaultSubtitle = type === 'welcome' ? 'sur le serveur Discord' : 'a quitté le serveur';
|
||||
const displaySubtitle = subtitle || defaultSubtitle;
|
||||
|
||||
ctx.font = '22px Arial, sans-serif';
|
||||
ctx.shadowBlur = 3;
|
||||
ctx.fillText(displaySubtitle, textX, 110);
|
||||
|
||||
// Nom du serveur (en italique)
|
||||
ctx.font = 'italic 28px Arial, sans-serif';
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillText(serverName, textX, 150);
|
||||
|
||||
// Reset shadow
|
||||
ctx.shadowColor = 'transparent';
|
||||
ctx.shadowBlur = 0;
|
||||
|
||||
// Nom d'utilisateur
|
||||
ctx.font = 'bold 26px Arial, sans-serif';
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
|
||||
|
||||
let userDisplay = username;
|
||||
if (discriminator && discriminator !== '0') {
|
||||
userDisplay += `#${discriminator}`;
|
||||
}
|
||||
|
||||
// Tronquer si trop long
|
||||
if (ctx.measureText(userDisplay).width > 350) {
|
||||
while (ctx.measureText(userDisplay + '...').width > 350 && userDisplay.length > 0) {
|
||||
userDisplay = userDisplay.slice(0, -1);
|
||||
}
|
||||
userDisplay += '...';
|
||||
}
|
||||
|
||||
ctx.fillText(userDisplay, textX, 195);
|
||||
|
||||
// Nombre de membres (optionnel)
|
||||
if (memberCount) {
|
||||
ctx.font = '16px Arial, sans-serif';
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
|
||||
const memberText = type === 'welcome'
|
||||
? `Tu es le ${memberCount}ème membre !`
|
||||
: `Il reste ${memberCount} membres`;
|
||||
ctx.fillText(memberText, textX, 225);
|
||||
}
|
||||
|
||||
return canvas.toBuffer('image/png');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dessine un rectangle aux coins arrondis
|
||||
*/
|
||||
function roundRect(ctx, x, y, width, height, radius) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + radius, y);
|
||||
ctx.lineTo(x + width - radius, y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
||||
ctx.lineTo(x + width, y + height - radius);
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
||||
ctx.lineTo(x + radius, y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
||||
ctx.lineTo(x, y + radius);
|
||||
ctx.quadraticCurveTo(x, y, x + radius, y);
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
// Liste des dégradés disponibles pour le frontend
|
||||
const availableGradients = Object.keys(GRADIENTS);
|
||||
|
||||
module.exports = { generateWelcomeImage, availableGradients, GRADIENTS };
|
||||
Reference in New Issue
Block a user