mirror of
https://github.com/arthur-pbty/LazyBot.git
synced 2026-06-03 15:07:29 +02:00
fac4b0c9e5
- 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.
210 lines
6.4 KiB
JavaScript
210 lines
6.4 KiB
JavaScript
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 };
|