mirror of
https://github.com/arthur-pbty/discord-weather-bot.git
synced 2026-08-01 20:28:48 +02:00
119 lines
5.6 KiB
JavaScript
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);
|
|
});
|