hopefully fixed the global commands not appearing in dms 🙏 🙏 🙏
This commit is contained in:
parent
d2e2f30349
commit
974b356d98
306
discord/index.js
306
discord/index.js
|
@ -11,8 +11,19 @@ const axios = require("axios");
|
|||
const ping = require("ping");
|
||||
|
||||
const client = new Client({
|
||||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.DirectMessages],
|
||||
});
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.DirectMessages,
|
||||
GatewayIntentBits.MessageContent,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.DirectMessageReactions,
|
||||
GatewayIntentBits.DirectMessageTyping,
|
||||
GatewayIntentBits.GuildMessageReactions,
|
||||
GatewayIntentBits.GuildMessageTyping
|
||||
],
|
||||
partials: ['CHANNEL', 'MESSAGE'] // This is important for DM functionality
|
||||
});
|
||||
|
||||
|
||||
// Original slash commands
|
||||
const slashCommands = [
|
||||
|
@ -20,6 +31,8 @@ const slashCommands = [
|
|||
name: "fetch_data",
|
||||
description: "Fetches data from an API",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
|
||||
options: [
|
||||
{
|
||||
name: "url",
|
||||
|
@ -33,6 +46,7 @@ const slashCommands = [
|
|||
name: "ping",
|
||||
description: "Pings a remote server.",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "ip",
|
||||
|
@ -46,6 +60,7 @@ const slashCommands = [
|
|||
name: "server_status",
|
||||
description: "Fetches data from an API",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "raw",
|
||||
|
@ -60,6 +75,7 @@ const slashCommands = [
|
|||
name: "cody",
|
||||
description: "Ask Cody (Sourcegraph AI) a coding question",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "question",
|
||||
|
@ -74,6 +90,7 @@ const slashCommands = [
|
|||
name: "weather",
|
||||
description: "Get current weather for a location",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "location",
|
||||
|
@ -83,6 +100,75 @@ const slashCommands = [
|
|||
},
|
||||
],
|
||||
},
|
||||
// Add Minecraft server status command
|
||||
{
|
||||
name: "mcstatus",
|
||||
description: "Check the status of a Minecraft server",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "server",
|
||||
description: "Server address (e.g., mc.hypixel.net)",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "bedrock",
|
||||
description: "Is this a Bedrock server? (Default: false)",
|
||||
type: ApplicationCommandOptionType.Boolean,
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "animal",
|
||||
description: "Get a random animal image",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "type",
|
||||
description: "Type of animal",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
choices: [
|
||||
{ name: "Dog", value: "dog" },
|
||||
{ name: "Cat", value: "cat" },
|
||||
{ name: "Panda", value: "panda" },
|
||||
{ name: "Fox", value: "fox" },
|
||||
{ name: "Bird", value: "bird" },
|
||||
{ name: "Koala", value: "koala" },
|
||||
{ name: "Red Panda", value: "red_panda" },
|
||||
{ name: "Raccoon", value: "raccoon" },
|
||||
{ name: "Kangaroo", value: "kangaroo" }
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
// Add Anime commands
|
||||
{
|
||||
name: "anime",
|
||||
description: "Get anime-related content",
|
||||
type: ApplicationCommandType.ChatInput,
|
||||
dm_permission: true,
|
||||
options: [
|
||||
{
|
||||
name: "type",
|
||||
description: "Type of anime content",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
choices: [
|
||||
{ name: "Wink", value: "wink" },
|
||||
{ name: "Pat", value: "pat" },
|
||||
{ name: "Hug", value: "hug" },
|
||||
{ name: "Face Palm", value: "face-palm" },
|
||||
{ name: "Quote", value: "quote" }
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
// User context menu commands
|
||||
|
@ -128,6 +214,10 @@ async function askCody(question) {
|
|||
throw new Error("SOURCEGRAPH_API_KEY is not set in environment variables");
|
||||
}
|
||||
|
||||
if (question.length > 1999) {
|
||||
throw new Error("Input question is too long - must be 1999 characters or less");
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
method: 'post',
|
||||
|
@ -185,13 +275,26 @@ async function askCody(question) {
|
|||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
client.once("ready", async () => {
|
||||
}client.once("ready", async () => {
|
||||
console.log(`Logged in as ${client.user.tag}`);
|
||||
await updateCommands();
|
||||
|
||||
const ownerId = process.env.OWNER_ID;
|
||||
const owner = await client.users.fetch(ownerId);
|
||||
await owner.send(`Bot started successfully at ${new Date().toLocaleString()}`);
|
||||
});
|
||||
|
||||
client.on("interactionCreate", async (interaction) => {
|
||||
// Safe channel type logging
|
||||
console.log(`Interaction received in: ${interaction.channel?.type || 'Unknown channel type'}`);
|
||||
console.log(`Command name: ${interaction.commandName}`);
|
||||
console.log(`Channel: ${interaction.channel?.id || 'No channel'}`);
|
||||
|
||||
// Rest of your existing handler code...
|
||||
});
|
||||
|
||||
|
||||
|
||||
client.on("interactionCreate", async (interaction) => {
|
||||
// Handle slash commands
|
||||
if (interaction.isChatInputCommand()) {
|
||||
|
@ -282,9 +385,12 @@ client.on("interactionCreate", async (interaction) => {
|
|||
// Format the response
|
||||
let formattedResponse = codyResponse || "No response received from Cody.";
|
||||
|
||||
// Calculate total length including the question
|
||||
const fullResponse = `**Question:** ${question}\n\n**Cody's Answer:**\n${formattedResponse}`;
|
||||
|
||||
// If the response is too long for Discord (which has a 2000 character limit)
|
||||
if (formattedResponse.length > 1900) {
|
||||
formattedResponse = formattedResponse.substring(0, 1900) + "...\n(Response truncated due to Discord's character limit)";
|
||||
if (fullResponse.length > 1900) {
|
||||
formattedResponse = formattedResponse.substring(0, 1900 - question.length - 50) + "...\n(Response truncated due to Discord's character limit)";
|
||||
}
|
||||
|
||||
await interaction.editReply({
|
||||
|
@ -296,8 +402,7 @@ client.on("interactionCreate", async (interaction) => {
|
|||
content: "Sorry, I couldn't get an answer from Cody. Please try again later.",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case "weather":
|
||||
try {
|
||||
|
@ -313,14 +418,13 @@ client.on("interactionCreate", async (interaction) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const weatherUrl = `https://api.weatherapi.com/v1/forecast.json?key=${process.env.WEATHER_API_KEY}&q=${encodeURIComponent(location)}&aqi=no&days=1`;
|
||||
const weatherUrl = `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${encodeURIComponent(location)}&aqi=no`;
|
||||
const response = await axios.get(weatherUrl);
|
||||
|
||||
const data = response.data;
|
||||
const location_name = data.location.name;
|
||||
const region = data.location.region;
|
||||
const country = data.location.country;
|
||||
const localTime = data.location.localtime;
|
||||
const temp_c = data.current.temp_c;
|
||||
const temp_f = data.current.temp_f;
|
||||
const condition = data.current.condition.text;
|
||||
|
@ -329,21 +433,15 @@ client.on("interactionCreate", async (interaction) => {
|
|||
const wind_mph = data.current.wind_mph;
|
||||
const feelslike_c = data.current.feelslike_c;
|
||||
const feelslike_f = data.current.feelslike_f;
|
||||
const maxtemp_c = data.forecast.forecastday[0].day.maxtemp_c;
|
||||
const maxtemp_f = data.forecast.forecastday[0].day.maxtemp_f;
|
||||
const mintemp_c = data.forecast.forecastday[0].day.mintemp_c;
|
||||
const mintemp_f = data.forecast.forecastday[0].day.mintemp_f;
|
||||
|
||||
const weatherEmbed = {
|
||||
title: `Weather for ${location_name}, ${region}, ${country}`,
|
||||
description: `Current condition: ${condition}\nLocal time: ${localTime}`,
|
||||
description: `Current condition: ${condition}`,
|
||||
fields: [
|
||||
{ name: 'Temperature', value: `${temp_c}°C / ${temp_f}°F`, inline: true },
|
||||
{ name: 'Feels Like', value: `${feelslike_c}°C / ${feelslike_f}°F`, inline: true },
|
||||
{ name: 'Humidity', value: `${humidity}%`, inline: true },
|
||||
{ name: 'Wind Speed', value: `${wind_kph} km/h / ${wind_mph} mph`, inline: true },
|
||||
{ name: 'Max Temperature', value: `${maxtemp_c}°C / ${maxtemp_f}°F`, inline: true },
|
||||
{ name: 'Min Temperature', value: `${mintemp_c}°C / ${mintemp_f}°F`, inline: true }
|
||||
{ name: 'Wind Speed', value: `${wind_kph} km/h / ${wind_mph} mph`, inline: true }
|
||||
],
|
||||
thumbnail: { url: `https:${data.current.condition.icon}` },
|
||||
timestamp: new Date(),
|
||||
|
@ -352,32 +450,166 @@ client.on("interactionCreate", async (interaction) => {
|
|||
|
||||
await interaction.editReply({ embeds: [weatherEmbed] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.editReply({
|
||||
content: "Failed to fetch weather data. Please check the location name and try again.",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
// In the mcstatus command handler, replace the thumbnail section with this:
|
||||
case "mcstatus":
|
||||
try {
|
||||
await interaction.deferReply();
|
||||
const serverAddress = interaction.options.getString("server");
|
||||
const isBedrock = interaction.options.getBoolean("bedrock") ?? false;
|
||||
|
||||
// Determine which API endpoint to use based on server type
|
||||
const apiUrl = isBedrock
|
||||
? `https://api.mcsrvstat.us/bedrock/2/${encodeURIComponent(serverAddress)}`
|
||||
: `https://api.mcsrvstat.us/2/${encodeURIComponent(serverAddress)}`;
|
||||
|
||||
const response = await axios.get(apiUrl);
|
||||
const data = response.data;
|
||||
|
||||
if (!data.online) {
|
||||
await interaction.editReply({
|
||||
content: `📡 **${serverAddress}** is currently offline or could not be reached.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle user context menu commands
|
||||
else if (interaction.isUserContextMenuCommand()) {
|
||||
switch (interaction.commandName) {
|
||||
case "User Info":
|
||||
try {
|
||||
const user = interaction.targetUser;
|
||||
await interaction.reply({
|
||||
content: `User info:\n• Tag: ${user.tag}\n• ID: ${user.id}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.reply({ content: "Failed to retrieve user info.", ephemeral: true });
|
||||
}
|
||||
break;
|
||||
|
||||
// Create a rich embed for the server status
|
||||
const serverEmbed = {
|
||||
title: `Minecraft Server Status: ${serverAddress}`,
|
||||
color: 0x44FF44, // Green color
|
||||
// Use a default Minecraft image instead of trying to use the base64 icon
|
||||
thumbnail: {
|
||||
url: 'https://www.minecraft.net/content/dam/games/minecraft/key-art/MC_The-Wild-Update_540x300.jpg'
|
||||
},
|
||||
fields: [
|
||||
{ name: 'Status', value: data.online ? '✅ Online' : '❌ Offline', inline: true },
|
||||
{ name: 'Players', value: data.players ? `${data.players.online}/${data.players.max}` : 'Unknown', inline: true },
|
||||
{ name: 'Version', value: data.version || 'Unknown', inline: true }
|
||||
],
|
||||
footer: { text: 'Powered by mcsrvstat.us' },
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
// Add MOTD if available
|
||||
if (data.motd && data.motd.clean && data.motd.clean.length > 0) {
|
||||
serverEmbed.description = `**MOTD:**\n${data.motd.clean.join('\n')}`;
|
||||
}
|
||||
|
||||
// Add player list if available and not empty
|
||||
if (data.players && data.players.list && data.players.list.length > 0) {
|
||||
// Limit to first 20 players to avoid hitting Discord's limits
|
||||
const playerList = data.players.list.slice(0, 20).join(', ');
|
||||
const hasMore = data.players.list.length > 20;
|
||||
|
||||
serverEmbed.fields.push({
|
||||
name: 'Online Players',
|
||||
value: playerList + (hasMore ? '...' : '')
|
||||
});
|
||||
}
|
||||
|
||||
await interaction.editReply({ embeds: [serverEmbed] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.editReply({
|
||||
content: "Failed to fetch Minecraft server status. Please check the server address and try again.",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "animal":
|
||||
try {
|
||||
await interaction.deferReply();
|
||||
const animalType = interaction.options.getString("type");
|
||||
|
||||
// Get animal image
|
||||
const imageResponse = await axios.get(`https://some-random-api.com/animal/${animalType}`);
|
||||
const imageUrl = imageResponse.data.image;
|
||||
|
||||
const animalEmbed = {
|
||||
color: 0x3498db,
|
||||
image: { url: imageUrl },
|
||||
footer: { text: 'Powered by some-random-api.com' },
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
await interaction.editReply({ embeds: [animalEmbed] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.editReply({
|
||||
content: "Failed to fetch animal image. The API might be down or the animal type is not available.",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "anime":
|
||||
try {
|
||||
await interaction.deferReply();
|
||||
const action = interaction.options.getString("action");
|
||||
|
||||
let apiUrl;
|
||||
let isQuote = false;
|
||||
|
||||
if (action === "quote") {
|
||||
apiUrl = "https://some-random-api.ml/animu/quote";
|
||||
isQuote = true;
|
||||
} else {
|
||||
apiUrl = `https://some-random-api.ml/animu/${action}`;
|
||||
}
|
||||
|
||||
const response = await axios.get(apiUrl);
|
||||
|
||||
if (isQuote) {
|
||||
// Handle quote response
|
||||
const quote = response.data.sentence;
|
||||
const character = response.data.character;
|
||||
const anime = response.data.anime;
|
||||
|
||||
const quoteEmbed = {
|
||||
title: "Anime Quote",
|
||||
description: `"${quote}"`,
|
||||
fields: [
|
||||
{ name: "Character", value: character, inline: true },
|
||||
{ name: "Anime", value: anime, inline: true }
|
||||
],
|
||||
color: 0xe74c3c,
|
||||
footer: { text: 'Powered by some-random-api.ml' },
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
await interaction.editReply({ embeds: [quoteEmbed] });
|
||||
} else {
|
||||
// Handle GIF response
|
||||
const gifUrl = response.data.link;
|
||||
|
||||
const actionTitle = action.charAt(0).toUpperCase() + action.slice(1).replace('-', ' ');
|
||||
|
||||
const gifEmbed = {
|
||||
title: `Anime ${actionTitle}`,
|
||||
color: 0xe74c3c,
|
||||
image: { url: gifUrl },
|
||||
footer: { text: 'Powered by some-random-api.ml' },
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
await interaction.editReply({ embeds: [gifEmbed] });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.editReply({
|
||||
content: "Failed to fetch anime content. The API might be down or the requested action is not available.",
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}});
|
||||
client.login(process.env.DISCORD_TOKEN);
|
Loading…
Reference in a new issue