Files
discord-weather-bot/index.js
T
2026-06-19 07:18:00 +02:00

119 lines
5.6 KiB
JavaScript

'use strict';
require('dotenv').config();
const { Client, GatewayIntentBits, Collection, REST, Routes } = require('discord.js');
const cron = require('node-cron');
const path = require('path');
const fs = require('fs');
// ─── Validation des variables d'environnement ─────────────────────────────────
const REQUIRED_ENV = ['DISCORD_TOKEN', 'CHANNEL_ID', 'LAT', 'LON'];
for (const key of REQUIRED_ENV) {
if (!process.env[key]) {
console.error(`❌ Variable d'environnement manquante : ${key}`);
process.exit(1);
}
}
// ─── Client Discord ───────────────────────────────────────────────────────────
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.commands = new Collection();
// ─── Chargement des commandes ─────────────────────────────────────────────────
const commandsDir = path.join(__dirname, 'commands');
for (const file of fs.readdirSync(commandsDir).filter(f => f.endsWith('.js'))) {
const cmd = require(path.join(commandsDir, file));
if (!cmd.data || !cmd.execute) {
console.warn(`⚠️ Commande ignorée (structure invalide) : ${file}`);
continue;
}
client.commands.set(cmd.data.name, cmd);
console.log(`✅ Commande chargée : /${cmd.data.name}`);
}
// ─── Prêt ─────────────────────────────────────────────────────────────────────
client.once('ready', async () => {
console.log(`\n🤖 Connecté en tant que ${client.user.tag}`);
console.log(`📍 Localisation : ${process.env.LOCATION_NAME || `${process.env.LAT}°, ${process.env.LON}°`}`);
console.log(`⏰ Message quotidien : ${process.env.SEND_HOUR}h${String(process.env.SEND_MINUTE || 0).padStart(2,'0')}\n`);
// ── Enregistrement global des commandes slash ──────────────────────────────
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
const payload = [...client.commands.values()].map(c => c.data.toJSON());
try {
console.log('📡 Enregistrement des commandes slash (global)…');
await rest.put(Routes.applicationCommands(client.user.id), { body: payload });
console.log(`✅ ${payload.length} commande(s) enregistrée(s)\n`);
} catch (err) {
console.error('❌ Erreur enregistrement commandes :', err.message);
}
// ── Cron : message météo quotidien ────────────────────────────────────────
const hour = parseInt(process.env.SEND_HOUR, 10) || 7;
const minute = parseInt(process.env.SEND_MINUTE, 10) || 30;
const cronExpr = `${minute} ${hour} * * *`;
cron.schedule(cronExpr, async () => {
console.log(`\n⏰ [${new Date().toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })}] Envoi du rapport météo quotidien…`);
// Invalider le cache pour forcer un rafraîchissement
require('./services/weather').invalidateCache();
require('./services/astronomy').invalidateAstroCache();
try {
const channel = await client.channels.fetch(process.env.CHANNEL_ID);
if (!channel?.isTextBased()) {
console.error('❌ Channel introuvable ou non textuel :', process.env.CHANNEL_ID);
return;
}
const { sendWeatherReport } = require('./commands/meteo');
await sendWeatherReport(channel, false);
console.log('✅ Rapport météo quotidien envoyé.');
} catch (err) {
console.error('❌ Erreur envoi quotidien :', err.message);
}
}, { timezone: 'Europe/Paris' });
console.log(`⏰ Cron programmé : "${cronExpr}" (Europe/Paris)`);
});
// ─── Gestion des interactions ─────────────────────────────────────────────────
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) {
console.warn(`⚠️ Commande inconnue reçue : ${interaction.commandName}`);
return;
}
try {
await command.execute(interaction);
} catch (err) {
console.error(`❌ Erreur commande /${interaction.commandName} :`, err);
const errMsg = { content: `❌ Une erreur inattendue est survenue.`, ephemeral: true };
if (interaction.replied || interaction.deferred) {
await interaction.followUp(errMsg).catch(() => {});
} else {
await interaction.reply(errMsg).catch(() => {});
}
}
});
// ─── Erreurs non gérées ───────────────────────────────────────────────────────
process.on('unhandledRejection', (reason, promise) => {
console.error('⚠️ UnhandledRejection :', reason);
});
process.on('uncaughtException', (err) => {
console.error('💥 UncaughtException :', err);
});
// ─── Connexion ────────────────────────────────────────────────────────────────
client.login(process.env.DISCORD_TOKEN).catch(err => {
console.error('❌ Connexion Discord échouée :', err.message);
process.exit(1);
});