develop #2

Merged
jack merged 10 commits from develop into main 2024-09-16 14:50:32 +00:00
8 changed files with 125 additions and 68 deletions
Showing only changes of commit 3a9fc1897a - Show all commits

View File

@@ -1,17 +1,17 @@
{
"name": "butlerbotng",
"name": "butlerbot",
"version": "1.0.0",
"main": "dist/index.js",
"scripts": {
"start": "node dist/index.js",
"build": "tsup src/index.ts --minify",
"register-slash-commands": "tsx src/register-slash-commands.ts",
"register-slash-commands": "tsx src/registerSlashCommands.ts",
"dev": "tsx watch src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://git.3t.network/terriblecodeclub/butlerbotng.git"
"url": "https://git.3t.network/terriblecodeclub/butlerbot.git"
},
"author": "Butlersaurus",
"license": "ISC",
@@ -23,13 +23,13 @@
"dotenv": "^16.4.5",
"glob": "^11.0.0",
"mongodb": "^6.8.1",
"prettier": "^3.3.3",
"replicate": "^0.32.1"
},
"devDependencies": {
"@types/glob": "^8.1.0",
"@types/node": "^20.4.0",
"eslint": "^9.9.1",
"prettier": "^3.3.3",
"ts-node": "^10.9.1",
"tsup": "^8.2.4",
"tsx": "^4.19.1",

View File

@@ -1,33 +0,0 @@
import * as birthday from './commands/birthday';
import * as corrupt from './commands/corrupt';
import * as countdown from './commands/countdown';
import * as eyecandy from './commands/eyecandy';
import * as game from './commands/game';
import * as image from './commands/image';
import * as imdb from './commands/imdb';
import * as kanye from './commands/kanye';
import * as magicEightBall from './commands/magic8Ball';
import * as payday from './commands/payday';
import * as plant from './commands/plant';
import * as reminder from './commands/reminder';
import * as servertime from './commands/servertime';
import * as taylor from './commands/taylor';
import * as twentyTwenty from './commands/twentyTwenty';
export const commands = {
birthday,
corrupt,
countdown,
eyecandy,
game,
image,
imdb,
kanye,
magicEightBall,
payday,
plant,
reminder,
servertime,
taylor,
twentyTwenty,
};

View File

@@ -10,9 +10,10 @@ interface Config {
omdbApiKey: string;
replicateApiKey: string;
mongodbUri: string;
registerSlashCommands?: boolean;
}
const getEnv = (key: string, required = true): string | undefined => {
const getEnv = (key: string, required = true): string | boolean | undefined => {
const value = process.env[key];
if (!value && required) {
throw new Error(`${key} is not set in the environment variables.`);
@@ -28,6 +29,7 @@ const config: Config = {
omdbApiKey: getEnv('OMDB_API_KEY') as string,
replicateApiKey: getEnv('REPLICATE_API_KEY') as string,
mongodbUri: getEnv('MONGODB_URI') as string,
registerSlashCommands: getEnv('REGISTER_SLASH_COMMANDS', false) as boolean,
};
export default config;

View File

@@ -6,25 +6,50 @@ import {
GatewayIntentBits,
Interaction,
} from 'discord.js';
import { commands } from './commands';
import { getCommands, registerSlashCommands } from './utils/commands';
import { Command } from './utils/types';
import config from './config';
// Define an extended version of the Client interface to include commands
interface ExtendedClient extends Client {
commands: Collection<string, any>;
commands: Collection<string, Command>;
}
const client: ExtendedClient = new Client({
intents: [GatewayIntentBits.Guilds],
}) as ExtendedClient;
// Add the commands to the client
client.commands = getCommands();
// If REGISTER_SLASH_COMMANDS is set to true, register the commands.
if (config.registerSlashCommands) {
registerSlashCommands(client.commands)
.then(() => {
console.log('Successfully registered slash commands');
})
.catch((error) => {
console.error('Failed to register slash commands:', error);
process.exit(1);
});
}
// Register the event listener for command interactions.
client.on(Events.InteractionCreate, async (interaction: Interaction) => {
if (!interaction.isChatInputCommand()) return;
const { commandName } = interaction;
const command = client.commands.get(interaction.commandName);
if (commands[commandName as keyof typeof commands]) {
commands[commandName as keyof typeof commands].execute(interaction);
if (command) {
try {
await command.execute(interaction);
} catch (error) {
console.error(`Error executing ${interaction.commandName}:`, error);
await interaction.reply({
content: 'There was an error executing that command!',
ephemeral: true,
});
}
}
});

View File

@@ -1,25 +0,0 @@
import { REST, Routes } from 'discord.js';
import { commands } from './commands';
import config from './config';
// Register all slash commands, globally across all Guilds.
const commandData = Object.values(commands).map(
(command) => command.data.toJSON() as any
);
const rest = new REST().setToken(config.discordApiKey);
try {
console.log('Started refreshing application (/) commands.');
// Refresh all slash commands globally.
rest.put(Routes.applicationCommands(config.discordApplicationId), {
body: commandData,
});
// Exit the process.
process.exit();
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}

View File

@@ -0,0 +1,12 @@
import { getCommands, registerSlashCommands } from './utils/commands';
const commands = getCommands();
registerSlashCommands(commands)
.then(() => {
console.log('Successfully registered slash commands');
})
.catch((error) => {
console.error('Failed to register slash commands:', error);
process.exit(1);
});

58
src/utils/commands.ts Normal file
View File

@@ -0,0 +1,58 @@
import { Collection, REST, Routes } from 'discord.js';
import * as birthday from '../commands/birthday';
import * as corrupt from '../commands/corrupt';
import * as countdown from '../commands/countdown';
import * as eyecandy from '../commands/eyecandy';
import * as game from '../commands/game';
import * as image from '../commands/image';
import * as imdb from '../commands/imdb';
import * as kanye from '../commands/kanye';
import * as magicEightBall from '../commands/magic8Ball';
import * as payday from '../commands/payday';
import * as plant from '../commands/plant';
import * as reminder from '../commands/reminder';
import * as servertime from '../commands/servertime';
import * as taylor from '../commands/taylor';
import * as twentyTwenty from '../commands/twentyTwenty';
import config from '../config';
import { Command } from './types';
/**
* Get all commands as a collection.
* @returns A collection of commands.
*/
export function getCommands(): Collection<string, Command> {
const commands = new Collection<string, Command>();
commands.set(birthday.data.name, birthday);
commands.set(corrupt.data.name, corrupt);
commands.set(countdown.data.name, countdown);
commands.set(eyecandy.data.name, eyecandy);
commands.set(game.data.name, game);
commands.set(image.data.name, image);
commands.set(imdb.data.name, imdb);
commands.set(kanye.data.name, kanye);
commands.set(magicEightBall.data.name, magicEightBall);
commands.set(payday.data.name, payday);
commands.set(plant.data.name, plant);
commands.set(reminder.data.name, reminder);
commands.set(servertime.data.name, servertime);
commands.set(taylor.data.name, taylor);
commands.set(twentyTwenty.data.name, twentyTwenty);
return commands;
}
/**
* Register all slash commands globally across all Guilds.
* @param commands A collection of commands to register.
*/
export async function registerSlashCommands(
commands: Collection<string, Command>
) {
const commandData = commands.map((command) => command.data.toJSON());
const rest = new REST({ version: '10' }).setToken(config.discordApiKey);
await rest.put(Routes.applicationCommands(config.discordApplicationId), {
body: commandData,
});
}

18
src/utils/types.ts Normal file
View File

@@ -0,0 +1,18 @@
import {
SlashCommandBuilder,
SlashCommandSubcommandsOnlyBuilder,
SlashCommandOptionsOnlyBuilder,
ChatInputCommandInteraction,
} from 'discord.js';
// Create a generic type to cover all relevant SlashCommandBuilder types
export type CommandBuilder =
| SlashCommandBuilder
| SlashCommandSubcommandsOnlyBuilder
| SlashCommandOptionsOnlyBuilder;
// Define the Command interface
export interface Command {
data: CommandBuilder; // Use the generic CommandBuilder type
execute: (interaction: ChatInputCommandInteraction) => Promise<void>;
}