Add wiki and weather commands

This commit is contained in:
2026-01-26 14:10:46 +01:00
parent a86c90f8ce
commit ef7ca16a85
18 changed files with 266 additions and 48 deletions
+2 -1
View File
@@ -4,13 +4,14 @@ module.exports = {
data: new SlashCommandBuilder()
.setName('about')
.setDescription('Information about this bot and creator'),
category: 'Utility',
async execute(interaction) {
const exampleEmbed = new EmbedBuilder()
.setColor(0x0099FF)
.setTitle('About This Bot')
.setDescription('A multipurpose Discord bot focused on helpful utilities, moderation, and fun community features.')
.addFields(
{ name: 'Highlights', value: 'Timezone converter, quiz games, and a growing currency system.' },
{ name: 'Highlights', value: 'Timezone converter, quiz games, a currency system, and helpful utility tools.' },
{ name: 'Created By', value: interaction.client.user?.username ?? 'Bot Creator' }
)
.setImage('https://i.postimg.cc/QdZZwKVD/Screenshot-2024-12-25-005933.png')
+19 -4
View File
@@ -4,22 +4,37 @@ module.exports = {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Gives all available commands.'),
category: 'Utility',
async execute(interaction) {
const commandDetails = interaction.client.commands
.map(cmd => ({
name: cmd.data.name,
description: cmd.data.description,
category: cmd.category ?? 'Other',
}))
.sort((a, b) => a.name.localeCompare(b.name));
const helpMessage = commandDetails
.map(detail => `• **/${detail.name}** — ${detail.description}`)
.join('\n');
const grouped = commandDetails.reduce((acc, command) => {
const group = acc[command.category] ?? [];
group.push(command);
acc[command.category] = group;
return acc;
}, {});
const fields = Object.keys(grouped)
.sort((a, b) => a.localeCompare(b))
.map((category) => ({
name: category,
value: grouped[category]
.map(command => `• **/${command.name}** — ${command.description}`)
.join('\n'),
}));
const embed = new EmbedBuilder()
.setColor(0x4b7bec)
.setTitle('Available Commands')
.setDescription(helpMessage)
.setDescription('Here is everything I can do right now.')
.addFields(fields)
.setFooter({ text: `${commandDetails.length} commands loaded.` });
await interaction.reply({ embeds: [embed], ephemeral: true });
+12 -4
View File
@@ -1,17 +1,25 @@
const { SlashCommandBuilder } = require('discord.js');
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Check the bot\'s responsiveness.'),
category: 'Utility',
async execute(interaction) {
const sentAt = Date.now();
await interaction.reply({ content: 'Pinging...', ephemeral: true });
const latency = Date.now() - sentAt;
const apiLatency = Math.round(interaction.client.ws.ping);
await interaction.editReply({
content: `Pong! **${latency}ms** (API: **${apiLatency}ms**)`,
});
const embed = new EmbedBuilder()
.setColor(0x34ace0)
.setTitle('Pong! 🏓')
.addFields(
{ name: 'Round Trip', value: `${latency}ms`, inline: true },
{ name: 'API Latency', value: `${apiLatency}ms`, inline: true },
)
.setTimestamp();
await interaction.editReply({ embeds: [embed], content: null });
},
};
+23 -3
View File
@@ -1,10 +1,30 @@
const { SlashCommandBuilder } = require('discord.js');
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('server')
.setDescription('Provides information about the server.'),
category: 'Utility',
async execute(interaction) {
await interaction.reply(`This server is ${interaction.guild.name} and has ${interaction.guild.memberCount} members.`);
const { guild } = interaction;
const owner = await guild.fetchOwner();
const created = `<t:${Math.floor(guild.createdTimestamp / 1000)}:F>`;
const boostCount = guild.premiumSubscriptionCount ?? 0;
const embed = new EmbedBuilder()
.setColor(0x2ecc71)
.setTitle(guild.name)
.setThumbnail(guild.iconURL({ size: 256 }))
.addFields(
{ name: 'Server ID', value: guild.id, inline: true },
{ name: 'Owner', value: owner.user.tag, inline: true },
{ name: 'Members', value: guild.memberCount.toString(), inline: true },
{ name: 'Boosts', value: boostCount.toString(), inline: true },
{ name: 'Created', value: created, inline: false },
)
.setFooter({ text: `Requested by ${interaction.user.tag}` })
.setTimestamp();
await interaction.reply({ embeds: [embed], ephemeral: true });
},
};
};
+26 -4
View File
@@ -1,10 +1,32 @@
const { SlashCommandBuilder } = require('discord.js');
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('user')
.setDescription('Provides information about the user.'),
.setDescription('Provides information about a user.')
.addUserOption(option =>
option
.setName('target')
.setDescription('User to look up')
.setRequired(false)),
category: 'Utility',
async execute(interaction) {
await interaction.reply(`This command was run by ${interaction.user.username}, who joined on ${interaction.member.joinedAt}.`);
const target = interaction.options.getUser('target') ?? interaction.user;
const member = await interaction.guild.members.fetch(target.id);
const embed = new EmbedBuilder()
.setColor(0x4b7bec)
.setTitle(`${target.username}`)
.setThumbnail(target.displayAvatarURL({ size: 256 }))
.addFields(
{ name: 'Tag', value: target.tag, inline: true },
{ name: 'User ID', value: target.id, inline: true },
{ name: 'Account Created', value: `<t:${Math.floor(target.createdTimestamp / 1000)}:F>` },
{ name: 'Joined Server', value: member.joinedAt ? `<t:${Math.floor(member.joinedAt.getTime() / 1000)}:F>` : 'Unknown' },
)
.setFooter({ text: `Requested by ${interaction.user.tag}` })
.setTimestamp();
await interaction.reply({ embeds: [embed], ephemeral: true });
},
};
};
+72
View File
@@ -0,0 +1,72 @@
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const getJson = async (url) => {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Request failed with status ${response.status}`);
}
return response.json();
};
const formatTemperature = (value, unit) => `${Math.round(value)}°${unit === 'fahrenheit' ? 'F' : 'C'}`;
module.exports = {
data: new SlashCommandBuilder()
.setName('weather')
.setDescription('Get the current weather for a location.')
.addStringOption(option =>
option
.setName('location')
.setDescription('City or place name to look up')
.setRequired(true))
.addStringOption(option =>
option
.setName('units')
.setDescription('Temperature units')
.setRequired(false)
.addChoices(
{ name: 'Celsius', value: 'celsius' },
{ name: 'Fahrenheit', value: 'fahrenheit' },
)),
category: 'Utility',
async execute(interaction) {
const location = interaction.options.getString('location');
const units = interaction.options.getString('units') ?? 'celsius';
await interaction.deferReply();
try {
const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(location)}&count=1&language=en&format=json`;
const geo = await getJson(geoUrl);
const match = geo.results?.[0];
if (!match) {
return interaction.editReply({ content: 'I could not find that location. Try a more specific place name.' });
}
const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${match.latitude}&longitude=${match.longitude}&current_weather=true&temperature_unit=${units}`;
const weather = await getJson(weatherUrl);
const current = weather.current_weather;
if (!current) {
return interaction.editReply({ content: 'Weather data is currently unavailable for that location.' });
}
const embed = new EmbedBuilder()
.setColor(0x3498db)
.setTitle(`Weather for ${match.name}${match.country ? `, ${match.country}` : ''}`)
.addFields(
{ name: 'Temperature', value: formatTemperature(current.temperature, units), inline: true },
{ name: 'Wind Speed', value: `${Math.round(current.windspeed)} km/h`, inline: true },
{ name: 'Conditions', value: `Weather code: ${current.weathercode}`, inline: true },
)
.setFooter({ text: `Latitude ${match.latitude.toFixed(2)}, Longitude ${match.longitude.toFixed(2)}` })
.setTimestamp(new Date(current.time));
return interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error(error);
return interaction.editReply({ content: 'Something went wrong fetching the weather. Please try again later.' });
}
},
};
+54
View File
@@ -0,0 +1,54 @@
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const MAX_DESCRIPTION = 4096;
const truncate = (text, maxLength) => {
if (!text) return 'No summary available.';
if (text.length <= maxLength) return text;
return `${text.slice(0, maxLength - 3)}...`;
};
module.exports = {
data: new SlashCommandBuilder()
.setName('wiki')
.setDescription('Search Wikipedia for a topic.')
.addStringOption(option =>
option
.setName('topic')
.setDescription('Topic to search')
.setRequired(true)),
category: 'Utility',
async execute(interaction) {
const topic = interaction.options.getString('topic');
const endpoint = `https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(topic)}`;
await interaction.deferReply();
const response = await fetch(endpoint, {
headers: {
'User-Agent': 'DiscordBot/1.0 (https://github.com)',
},
});
if (!response.ok) {
return interaction.editReply({
content: 'I could not find a Wikipedia summary for that topic.',
});
}
const data = await response.json();
const embed = new EmbedBuilder()
.setColor(0x8e44ad)
.setTitle(data.title ?? topic)
.setURL(data.content_urls?.desktop?.page ?? `https://en.wikipedia.org/wiki/${encodeURIComponent(topic)}`)
.setDescription(truncate(data.extract, MAX_DESCRIPTION))
.setFooter({ text: 'Source: Wikipedia' });
if (data.thumbnail?.source) {
embed.setThumbnail(data.thumbnail.source);
}
return interaction.editReply({ embeds: [embed] });
},
};