Convert to Typescript
This commit is contained in:
33
src/commands.ts
Normal file
33
src/commands.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
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,
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import {
|
||||
format,
|
||||
differenceInYears,
|
||||
@@ -10,11 +10,21 @@ import {
|
||||
|
||||
const BIRTHDAY_TIMESTAMP = 1582576229;
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('birthday')
|
||||
.setDescription("Returns ButlerBot's Birthday information.");
|
||||
|
||||
async function execute(interaction) {
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Responds with ButlerBot's age and the time remaining until the next birthday.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const today = new Date();
|
||||
const birthday = new Date(BIRTHDAY_TIMESTAMP * 1000);
|
||||
|
||||
@@ -56,5 +66,3 @@ async function execute(interaction) {
|
||||
const fullMessage = `${ageMessage} ${birthdayMessage}`;
|
||||
await interaction.reply(fullMessage);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
24
src/commands/corrupt.ts
Normal file
24
src/commands/corrupt.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
|
||||
const CORRUPT_IMAGE =
|
||||
'https://media.discordapp.net/attachments/506852356898422797/717395817626861638/isntthatcorrupt2.PNG';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('corrupt')
|
||||
.setDescription(
|
||||
"Returns a powerful quote from Neil Breen's infamous indie film, Pass Thru (2016)."
|
||||
);
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Replies with an image from Neil Breen's Pass Thru (2016).
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.reply(CORRUPT_IMAGE);
|
||||
}
|
||||
31
src/commands/countdown.ts
Normal file
31
src/commands/countdown.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('countdown')
|
||||
.setDescription('Start a five second countdown.');
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Start a five second countdown and send updates to the user.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the countdown is finished.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.reply({ content: 'Starting countdown...' });
|
||||
|
||||
// 2-second delay before countdown starts
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
|
||||
// Countdown from 5 to 1
|
||||
for (let i = 5; i > 0; i--) {
|
||||
await interaction.editReply({ content: String(i) });
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000)); // 1-second delay between numbers
|
||||
}
|
||||
|
||||
// Notify the user that the countdown is over
|
||||
await interaction.editReply({ content: '🎉 GO! 🎉' });
|
||||
}
|
||||
@@ -1,32 +1,23 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import axios from 'axios';
|
||||
|
||||
const GIPHY_API_URL = 'http://api.giphy.com/v1/gifs/search';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('eyecandy')
|
||||
.setDescription('Returns a random gif of Gerard Butler.');
|
||||
|
||||
async function fetchGif() {
|
||||
const randomOffset = Math.floor(Math.random() * 100);
|
||||
const giphyQueryUrl = `${GIPHY_API_URL}?api_key=${process.env.GIPHY_API_KEY}&q=gerard+butler&limit=1&offset=${randomOffset}`;
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
try {
|
||||
const response = await axios.get(giphyQueryUrl, { timeout: 5000 });
|
||||
const result = response.data;
|
||||
|
||||
if (result.data.length === 0) {
|
||||
throw new Error('No gifs found for the given query.');
|
||||
}
|
||||
|
||||
return result.data[0].images.original.url;
|
||||
} catch (error) {
|
||||
console.error('Error fetching GIF:', error.message);
|
||||
throw new Error('Failed to retrieve a GIF from Giphy.');
|
||||
}
|
||||
}
|
||||
|
||||
async function execute(interaction) {
|
||||
/**
|
||||
* Execute the command, fetch a random Gerard Butler gif, and send it to the user.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (!process.env.GIPHY_API_KEY) {
|
||||
@@ -40,10 +31,32 @@ async function execute(interaction) {
|
||||
|
||||
// Reply with the gif.
|
||||
await interaction.editReply(gifUrl);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('Error executing the command:', error.message);
|
||||
await interaction.editReply(`An error occurred: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Fetch a random gif of Gerard Butler from Giphy.
|
||||
* @returns A promise that resolves to the URL of the gif.
|
||||
* @throws An error if no gif is found or if the request fails.
|
||||
*/
|
||||
async function fetchGif(): Promise<string> {
|
||||
const randomOffset = Math.floor(Math.random() * 100);
|
||||
const giphyQueryUrl = `${GIPHY_API_URL}?api_key=${process.env.GIPHY_API_KEY}&q=gerard+butler&limit=1&offset=${randomOffset}`;
|
||||
|
||||
try {
|
||||
const response = await axios.get(giphyQueryUrl, { timeout: 5000 });
|
||||
const result = response.data;
|
||||
|
||||
if (result.data.length === 0) {
|
||||
throw new Error('No gifs found for the given query.');
|
||||
}
|
||||
|
||||
return result.data[0].images.original.url;
|
||||
} catch (error: any) {
|
||||
console.error('Error fetching GIF:', error.message);
|
||||
throw new Error('Failed to retrieve a GIF from Giphy.');
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,18 @@
|
||||
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
|
||||
import {
|
||||
SlashCommandBuilder,
|
||||
EmbedBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import {
|
||||
listGameNames,
|
||||
getGame,
|
||||
setGame,
|
||||
deleteGame,
|
||||
deleteField,
|
||||
} from '../../utils/db/game.js';
|
||||
} from './utils/db/game';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('game')
|
||||
.setDescription('Perform ButlerBot game database operations.')
|
||||
.addSubcommand((subcommand) =>
|
||||
@@ -27,7 +32,7 @@ const data = new SlashCommandBuilder()
|
||||
.addSubcommand((subcommand) =>
|
||||
subcommand
|
||||
.setName('set')
|
||||
.setDescription('Set a key value pair on an game in the database.')
|
||||
.setDescription('Set a key value pair on a game in the database.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('game')
|
||||
@@ -69,24 +74,16 @@ const data = new SlashCommandBuilder()
|
||||
)
|
||||
);
|
||||
|
||||
function createEmbedFromGame(game) {
|
||||
const embed = new EmbedBuilder().setTitle(game.game).setColor(0xff0000);
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
// Add fields for each key value pair - skip name, _id and guild.
|
||||
embed.addFields(
|
||||
Object.entries(game)
|
||||
.filter(([key]) => !['_id', 'game', 'guild'].includes(key))
|
||||
.map(([key, value]) => ({ name: key, value: String(value) }))
|
||||
);
|
||||
|
||||
if (embed.length > 6000) {
|
||||
throw new Error('Embed size exceeds maximum.');
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
|
||||
async function execute(interaction) {
|
||||
/**
|
||||
* Handle the interaction for the game command.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
@@ -115,7 +112,7 @@ async function execute(interaction) {
|
||||
}
|
||||
|
||||
case 'get': {
|
||||
const gameName = interaction.options.getString('game');
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
|
||||
const game = await getGame(gameName);
|
||||
|
||||
@@ -138,9 +135,9 @@ async function execute(interaction) {
|
||||
}
|
||||
|
||||
case 'set': {
|
||||
const gameName = interaction.options.getString('game');
|
||||
const key = interaction.options.getString('key');
|
||||
const value = interaction.options.getString('value');
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
const key = interaction.options.getString('key', true);
|
||||
const value = interaction.options.getString('value', true);
|
||||
|
||||
const oldGame = await getGame(gameName);
|
||||
await setGame(gameName, key, value);
|
||||
@@ -167,7 +164,7 @@ async function execute(interaction) {
|
||||
}
|
||||
|
||||
case 'delete': {
|
||||
const gameName = interaction.options.getString('game');
|
||||
const gameName = interaction.options.getString('game', true);
|
||||
const key = interaction.options.getString('key');
|
||||
|
||||
if (key) {
|
||||
@@ -204,4 +201,24 @@ async function execute(interaction) {
|
||||
}
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Create an embed from a game object.
|
||||
* @param game The game object containing key-value pairs.
|
||||
* @returns The embed object to be sent in the interaction.
|
||||
*/
|
||||
function createEmbedFromGame(game: any): EmbedBuilder {
|
||||
const embed = new EmbedBuilder().setTitle(game.game).setColor(0xff0000);
|
||||
|
||||
// Add fields for each key value pair - skip name, _id and guild.
|
||||
embed.addFields(
|
||||
Object.entries(game)
|
||||
.filter(([key]) => !['_id', 'game', 'guild'].includes(key))
|
||||
.map(([key, value]) => ({ name: key, value: String(value) }))
|
||||
);
|
||||
|
||||
if (embed.length > 6000) {
|
||||
throw new Error('Embed size exceeds maximum.');
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
import { SlashCommandBuilder, AttachmentBuilder } from 'discord.js';
|
||||
import {
|
||||
SlashCommandBuilder,
|
||||
AttachmentBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import axios from 'axios';
|
||||
import Replicate from 'replicate';
|
||||
|
||||
if (!process.env.REPLICATE_API_KEY) {
|
||||
throw new Error('REPLICATE_API_KEY is not set in the environment variables.');
|
||||
}
|
||||
import Replicate, { Prediction } from 'replicate';
|
||||
import config from '../config';
|
||||
|
||||
const replicate = new Replicate({
|
||||
auth: process.env.REPLICATE_API_KEY,
|
||||
auth: config.replicateApiKey,
|
||||
});
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('image')
|
||||
.setDescription('Generate an image based on a prompt.')
|
||||
.addStringOption((option) =>
|
||||
@@ -20,48 +22,19 @@ const data = new SlashCommandBuilder()
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
// Helper function to poll the prediction status
|
||||
async function pollPredictionStatus(
|
||||
predictionId,
|
||||
maxAttempts = 5,
|
||||
interval = 2000
|
||||
) {
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
const latestPrediction = await replicate.predictions.get(predictionId);
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
if (
|
||||
latestPrediction.status !== 'starting' &&
|
||||
latestPrediction.status !== 'processing'
|
||||
) {
|
||||
return latestPrediction;
|
||||
}
|
||||
|
||||
// Wait before checking again
|
||||
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||
}
|
||||
|
||||
throw new Error('Prediction timed out.');
|
||||
}
|
||||
|
||||
// Helper function to download the image from a URL
|
||||
async function downloadImage(url) {
|
||||
try {
|
||||
const response = await axios.get(url, { responseType: 'arraybuffer' });
|
||||
return Buffer.from(response.data);
|
||||
} catch (error) {
|
||||
throw new Error('Failed to download the image.');
|
||||
}
|
||||
}
|
||||
|
||||
async function execute(interaction) {
|
||||
/**
|
||||
* Generate an image based on a prompt and send it back to the user.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (!process.env.REPLICATE_API_KEY) {
|
||||
await interaction.reply('The bot is missing the Replicate API key.');
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString('prompt');
|
||||
const prompt = interaction.options.get('prompt')?.value as string;
|
||||
|
||||
try {
|
||||
// Create image generation prediction
|
||||
@@ -89,11 +62,52 @@ async function execute(interaction) {
|
||||
|
||||
// Edit the deferred reply to include the generated image
|
||||
await interaction.editReply({ files: [attachment] });
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
// Provide a more informative error message to the user
|
||||
console.error(error); // Log the error for debugging purposes
|
||||
await interaction.editReply(`An error occurred: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Poll the status of a prediction until it is no longer in progress.
|
||||
* @param predictionId The ID of the prediction to poll.
|
||||
* @param maxAttempts The maximum number of attempts to poll the prediction.
|
||||
* @param interval The interval between each polling attempt in milliseconds.
|
||||
* @returns The final status of the prediction.
|
||||
*/
|
||||
async function pollPredictionStatus(
|
||||
predictionId: string,
|
||||
maxAttempts = 5,
|
||||
interval = 2000
|
||||
): Promise<Prediction> {
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
const latestPrediction = await replicate.predictions.get(predictionId);
|
||||
|
||||
if (
|
||||
latestPrediction.status !== 'starting' &&
|
||||
latestPrediction.status !== 'processing'
|
||||
) {
|
||||
return latestPrediction;
|
||||
}
|
||||
|
||||
// Wait before checking again
|
||||
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||
}
|
||||
|
||||
throw new Error('Prediction timed out.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an image from a URL and return it as a Buffer.
|
||||
* @param url The URL of the image to download.
|
||||
* @returns A Buffer containing the downloaded image.
|
||||
*/
|
||||
async function downloadImage(url: string): Promise<Buffer> {
|
||||
try {
|
||||
const response = await axios.get(url, { responseType: 'arraybuffer' });
|
||||
return Buffer.from(response.data);
|
||||
} catch (error) {
|
||||
throw new Error('Failed to download the image.');
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js';
|
||||
import {
|
||||
EmbedBuilder,
|
||||
SlashCommandBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import axios from 'axios';
|
||||
import config from '../config';
|
||||
|
||||
if (!process.env.OMDB_API_KEY) {
|
||||
throw new Error('OMDB_API_KEY is not set in the environment variables.');
|
||||
}
|
||||
|
||||
const OMDB_API_URL = 'http://www.omdbapi.com/?apikey={apiKey}';
|
||||
const OMDB_API_URL = `http://www.omdbapi.com/?apikey=${config.omdbApiKey}`;
|
||||
const FIELDS = [
|
||||
'Title',
|
||||
'Year',
|
||||
@@ -19,7 +20,7 @@ const FIELDS = [
|
||||
'BoxOffice',
|
||||
];
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('imdb')
|
||||
.setDescription('Return IMDB listing for the specified film.')
|
||||
.addStringOption((option) =>
|
||||
@@ -36,26 +37,20 @@ const data = new SlashCommandBuilder()
|
||||
.setMaxValue(2100)
|
||||
);
|
||||
|
||||
// Helper function to construct OMDB query URL
|
||||
function buildOmdbUrl(filmName, filmYear) {
|
||||
let url = OMDB_API_URL.replace('{apiKey}', process.env.OMDB_API_KEY);
|
||||
url += `&t=${encodeURIComponent(filmName.toLowerCase())}`;
|
||||
if (filmYear) {
|
||||
url += `&y=${filmYear}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
async function execute(interaction) {
|
||||
/**
|
||||
* Executes the 'imdb' command, retrieving film data from the OMDB API and sending it to the user.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (!process.env.OMDB_API_KEY) {
|
||||
await interaction.editReply('The bot is missing the OMDB API key.');
|
||||
return;
|
||||
}
|
||||
|
||||
const filmName = interaction.options.getString('film_name');
|
||||
const filmYear = interaction.options.getInteger('film_year');
|
||||
const filmName = interaction.options.getString('film_name') as string;
|
||||
const filmYear = interaction.options.getInteger('film_year') ?? undefined;
|
||||
|
||||
try {
|
||||
const omdbQueryUrl = buildOmdbUrl(filmName, filmYear);
|
||||
@@ -89,7 +84,7 @@ async function execute(interaction) {
|
||||
|
||||
// Send the result to the user
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error(`Error looking up film: ${filmName}`, error);
|
||||
await interaction.editReply(
|
||||
'An error occurred when querying the OMDB API.'
|
||||
@@ -97,4 +92,16 @@ async function execute(interaction) {
|
||||
}
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Helper function to construct OMDB query URL.
|
||||
* @param filmName The name of the film.
|
||||
* @param filmYear The year the film was released.
|
||||
* @returns The OMDB API URL with the specified query parameters.
|
||||
*/
|
||||
function buildOmdbUrl(filmName: string, filmYear?: number): string {
|
||||
let url = OMDB_API_URL + `&t=${encodeURIComponent(filmName.toLowerCase())}`;
|
||||
if (filmYear) {
|
||||
url += `&y=${filmYear}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
23
src/commands/kanye.ts
Normal file
23
src/commands/kanye.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import kanyeQuotes from './utils/constants/kanyeQuotes.json';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('kanye')
|
||||
.setDescription('Returns a Kanye West quote.');
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Returns a random Kanye West quote.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const randomIndex = Math.floor(Math.random() * kanyeQuotes.length);
|
||||
const response = kanyeQuotes[randomIndex];
|
||||
|
||||
await interaction.reply(response);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js';
|
||||
import axios from 'axios';
|
||||
|
||||
const GODADDY_API_URL = 'https://api.godaddy.com/v1/domains/available';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('domain')
|
||||
.setDescription('Check the availability and price of a domain name.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('domain')
|
||||
.setDescription('The domain to check')
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
async function execute(interaction) {
|
||||
const domain = interaction.options.getString('domain');
|
||||
let embed = new EmbedBuilder().setTitle('Domain checker');
|
||||
|
||||
try {
|
||||
const response = await axios.get(GODADDY_API_URL, {
|
||||
params: { domain: domain },
|
||||
headers: { Authorization: `sso-key ${process.env.GODADDY_API_KEY}` },
|
||||
timeout: 5000,
|
||||
});
|
||||
console.log(`Got response for domain: ${domain}.`, response.data);
|
||||
|
||||
const result = response.data;
|
||||
let isDomainAvailable = 'No.';
|
||||
let color = 0xff0000;
|
||||
let price = null;
|
||||
|
||||
if (response.status === 200 && result.available) {
|
||||
isDomainAvailable = 'Yes!';
|
||||
color = 0x00ff00;
|
||||
price = (result.price / 1000000).toFixed(2);
|
||||
}
|
||||
|
||||
embed.setColor(color).addFields({
|
||||
name: 'Is the domain available?',
|
||||
value: isDomainAvailable,
|
||||
});
|
||||
|
||||
if (price) {
|
||||
embed.addFields({ name: 'Price', value: `$${price}` });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error looking up domain: ${domain}.`, error);
|
||||
await interaction.reply('An error occurred when querying the GoDaddy API.');
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.reply({ embeds: [embed] });
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
31
src/commands/magic8Ball.ts
Normal file
31
src/commands/magic8Ball.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import magicEightBallResponses from './utils/constants/magicEightBallResponses.json';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('magic8ball')
|
||||
.setDescription('Returns a Magic 8 ball response.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('question')
|
||||
.setDescription('The question to ask the Magic 8 ball')
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Returns a random response from the Magic 8 ball.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const randomIndex = Math.floor(
|
||||
Math.random() * magicEightBallResponses.length
|
||||
);
|
||||
const response = magicEightBallResponses[randomIndex];
|
||||
|
||||
await interaction.reply(response);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const TWENTY_TWENTY_IMAGE =
|
||||
'https://cdn.discordapp.com/attachments/506852356898422797/765256712063025172/unknown.png';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('2020')
|
||||
.setDescription('Returns a tweet from Boris, posted on 2 January 2020.');
|
||||
|
||||
async function execute(interaction) {
|
||||
await interaction.reply(TWENTY_TWENTY_IMAGE);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,45 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('8ball')
|
||||
.setDescription('Returns a Magic 8 ball response.')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('question')
|
||||
.setDescription('The question to ask the Magic 8 ball')
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
const MAGIC_EIGHT_BALL_RESPONSES = [
|
||||
'As I see it, yes.',
|
||||
'Ask again later.',
|
||||
'Better not tell you now.',
|
||||
'Cannot predict now.',
|
||||
'Concentrate and ask again.',
|
||||
"Don't count on it.",
|
||||
'It is certain.',
|
||||
'It is decidedly so.',
|
||||
'Most likely.',
|
||||
'My reply is no.',
|
||||
'My sources say no.',
|
||||
'Outlook not so good.',
|
||||
'Outlook good.',
|
||||
'Reply hazy, try again.',
|
||||
'Signs point to yes.',
|
||||
'Very doubtful.',
|
||||
'Without a doubt.',
|
||||
'Yes.',
|
||||
'Yes - definitely.',
|
||||
'You may rely on it.',
|
||||
];
|
||||
|
||||
async function execute(interaction) {
|
||||
const randomIndex = Math.floor(
|
||||
Math.random() * MAGIC_EIGHT_BALL_RESPONSES.length
|
||||
);
|
||||
const response = MAGIC_EIGHT_BALL_RESPONSES[randomIndex];
|
||||
|
||||
await interaction.reply(response);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,16 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const CORRUPT_IMAGE =
|
||||
'https://media.discordapp.net/attachments/506852356898422797/717395817626861638/isntthatcorrupt2.PNG';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('corrupt')
|
||||
.setDescription(
|
||||
"Returns a powerful quote from Neil Breen's infamous indie film, Pass Thru (2016)."
|
||||
);
|
||||
|
||||
async function execute(interaction) {
|
||||
await interaction.reply(CORRUPT_IMAGE);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,139 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const KANYE_QUOTES = [
|
||||
'2024.',
|
||||
'All you have to be is yourself.',
|
||||
'Believe in your flyness... conquer your shyness.',
|
||||
'Burn that Excel spreadsheet.',
|
||||
'Decentralize.',
|
||||
'Distraction is the enemy of vision.',
|
||||
'Everything you do in life stems from either fear or love.',
|
||||
'For me giving up is way harder than trying.',
|
||||
'For me, money is not my definition of success. Inspiring people is a definition of success.',
|
||||
'Fur pillows are hard to actually sleep on.',
|
||||
"George Bush doesn't care about black people.",
|
||||
'Have you ever thought you were in love with someone but then realized you were just staring in a mirror for 20 minutes?',
|
||||
'I care. I care about everything. Sometimes not giving a f#%k is caring the most.',
|
||||
'I feel calm but energized.',
|
||||
"I feel like I'm too busy writing history to read it.",
|
||||
'I feel like me and Taylor might still have sex.',
|
||||
'I give up drinking every week.',
|
||||
'I leave my emojis Bart Simpson color.',
|
||||
"I love sleep; it's my favorite.",
|
||||
'I make awesome decisions in bike stores!!!',
|
||||
"I really love my Tesla. I'm in the future. Thank you Elon.",
|
||||
'I still think I am the greatest.',
|
||||
"I think I do myself a disservice by comparing myself to Steve Jobs and Walt Disney and human beings that we've seen before. It should be more like Willy Wonka...and welcome to my chocolate factory.",
|
||||
'I want the world to be better! All I want is positive! All I want is dopeness!',
|
||||
'I wish I had a friend like me.',
|
||||
"I'd like to meet with Tim Cook. I got some ideas.",
|
||||
"I'll say things that are serious and put them in a joke form so people can enjoy them. We laugh to keep from crying.",
|
||||
"I'm a creative genius.",
|
||||
"I'm nice at ping pong.",
|
||||
"I'm the best.",
|
||||
"If I don't scream, if I don't say something then no one's going to say anything.",
|
||||
'If I got any cooler I would freeze to death.',
|
||||
"If you have the opportunity to play this game of life you need to appreciate every moment. a lot of people don't appreciate the moment until it's passed.",
|
||||
'Just stop lying about shit. Just stop lying.',
|
||||
'Keep squares out yo circle.',
|
||||
'Keep your nose out the sky, keep your heart to god, and keep your face to the rising sun.',
|
||||
"Let's be like water.",
|
||||
'Man... whatever happened to my antique fish tank?',
|
||||
'My dad got me a drone for Christmas.',
|
||||
"My greatest award is what I'm about to do.",
|
||||
'My greatest pain in life is that I will never be able to see myself perform live.',
|
||||
"One day I'm gon' marry a porn star.",
|
||||
"One of my favorite of many things about what the Trump hat represents to me is that people can't tell me what to do because I'm black.",
|
||||
'Only free thinkers.',
|
||||
"People always say that you can't please everybody. I think that's a cop-out. Why not attempt it? Cause think of all the people that you will please if you try.",
|
||||
"People always tell you 'Be humble. Be humble.' When was the last time someone told you to be amazing? Be great! Be awesome! Be awesome!",
|
||||
'People only get jealous when they care.',
|
||||
'Perhaps I should have been more like water today.',
|
||||
'Pulling up in the may bike.',
|
||||
'Shut the fuck up I will fucking laser you with alien fucking eyes and explode your fucking head.',
|
||||
'Sometimes I push the door close button on people running towards the elevator. I just need my own elevator sometimes. My sanctuary.',
|
||||
'Sometimes you have to get rid of everything.',
|
||||
'Style is genderless.',
|
||||
'The thought police want to suppress freedom of thought.',
|
||||
'The world is our family.',
|
||||
'The world is our office.',
|
||||
"Today is the best day ever and tomorrow's going to be even better.",
|
||||
"Truth is my goal. Controversy is my gym. I'll do a hundred reps of controversy for a 6 pack of truth.",
|
||||
'Tweeting is legal and also therapeutic.',
|
||||
"We all self-conscious. I'm just the first to admit it.",
|
||||
"We came into a broken world. And we're the cleanup crew.",
|
||||
"You can't look at a glass half full or empty if it's overflowing.",
|
||||
"I hate when I'm on a flight and I wake up with a water bottle next to me like oh great now I gotta be responsible for this water bottle.",
|
||||
'All the musicians will be free.',
|
||||
'Artists are founders.',
|
||||
'Buy property.',
|
||||
'Culture is the most powerful force in humanity under God.',
|
||||
'Empathy is the glue.',
|
||||
'I am one of the most famous people on the planet.',
|
||||
'I am running for President of the United States.',
|
||||
'I am the head of Adidas. I will bring Adidas and Puma back together and bring me and jay back together.',
|
||||
'I am Warhol. I am the No. 1 most impactful artist of our generation. I am Shakespeare in the flesh.',
|
||||
"I channel Will Ferrell when I'm at the daddy daughter dances.",
|
||||
"I don't wanna see no woke tweets or hear no woke raps ... it's show time ... it's a whole different energy right now.",
|
||||
'I hear people say this person is cool and this person is not cool. People are cool. Man has never invented anything as awesome as a an actual person but sometimes we value the objects we create over life itself.',
|
||||
'I honestly need all my Royeres to be museum quality... if I see a fake Royere Ima have to Rick James your couch.',
|
||||
'I love UZI. I be saying the same thing about Steve Jobs. I be feeling just like UZI.',
|
||||
'I need an army of angels to cover me while I pull this sword out of the stone.',
|
||||
'I spoke to Dave Chapelle for two hours this morning. He is our modern day Socrates.',
|
||||
'I was just speaking with someone that told me their life story and they used to be homeless.',
|
||||
'I watch Bladerunner on repeat.',
|
||||
"I'm giving all Good music artists back the 50% share I have of their masters.",
|
||||
"I'm going to personally see to it that Taylor Swift gets her masters back. Scooter is a close family friend.",
|
||||
"I'm the new Moses.",
|
||||
'Life is the ultimate gift.',
|
||||
'Ma$e is one of my favorite rappers and I based a lot of my flows off of him.',
|
||||
'Manga all day.',
|
||||
"My first pillar when I'm on the board of adidas will be an adidas Nike collaboration to support community growth.",
|
||||
"My mama was a' English teacher. I know how to use correct English but sometimes I just don't feel like it aaaand I ain't got to.",
|
||||
'My memories are from the future.',
|
||||
'My mother in law Kris Jenner ... makes the best music playlist.',
|
||||
"People say it's enough and I got my point across ... the point isn't across until we cross the point.",
|
||||
'People tried to talk me out of running for President. Never let weak controlling people kill your spirit.',
|
||||
'So many of us need so much less than we have especially when so many of us are in need.',
|
||||
"Speak God's truth to power.",
|
||||
'The media tries to kill our heroes one at a time.',
|
||||
'The world needs more Joy... this idea is super fresh.',
|
||||
'There are 5 main pillars in a professional musicians business - Recording, Publishing, Touring, Merchandise & Name and likeness.',
|
||||
'There are people sleeping in parking lots.',
|
||||
"There's a crying need for civility across the board. We need to and will come together in the name of Jesus.",
|
||||
"There's so many lonely emojis man.",
|
||||
"Trust me ... I won't stop.",
|
||||
'Two years ago we had 50 million people subscribed to music streaming services around the world. Today we have 400 million.',
|
||||
'We are here to complete the revolution. We are building the future.',
|
||||
'We as a people will heal. We will insure the well being of each other.',
|
||||
'We have to evolve.',
|
||||
'We must and will cure homelessness and hunger. We have the capability as a species.',
|
||||
'We must form a union. We must unify.',
|
||||
'We used to diss Michael Jackson the media made us call him crazy ... then they killed him.',
|
||||
'We will be recognized.',
|
||||
'We will change the paradigm.',
|
||||
'We will cure hunger.',
|
||||
'We will heal. We will cure.',
|
||||
"We're going to move the entire music industry into the 21st Century.",
|
||||
"We've gotten comfortable with not having what we deserve.",
|
||||
'Who made up the term major label in the first place???',
|
||||
'Winning is the only option.',
|
||||
"For me to say I wasn't a genius I'd just be lying to you and to myself.",
|
||||
"I've known my mom since I was zero years old. She is quite dope.",
|
||||
"I don't expect to be understood at all.",
|
||||
"I'm on the pursuit of awesomeness, excellence is the bare minimum.",
|
||||
'You basically can say anything to someone on an email or text as long as you put LOL at the end.',
|
||||
];
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('kanye')
|
||||
.setDescription('Returns a random Kanye West quote.');
|
||||
|
||||
async function execute(interaction) {
|
||||
const randomIndex = Math.floor(Math.random() * KANYE_QUOTES.length);
|
||||
const quote = KANYE_QUOTES[randomIndex];
|
||||
|
||||
await interaction.reply(quote);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const REMINDER_IMAGE =
|
||||
'https://media.discordapp.net/attachments/506852356898422797/715690132883111996/Capture.PNG';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('reminder')
|
||||
.setDescription('Returns an image which must always be remembered.');
|
||||
|
||||
async function execute(interaction) {
|
||||
await interaction.reply(REMINDER_IMAGE);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,6 +1,9 @@
|
||||
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js';
|
||||
import {
|
||||
format,
|
||||
EmbedBuilder,
|
||||
SlashCommandBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import {
|
||||
addDays,
|
||||
subDays,
|
||||
getDay,
|
||||
@@ -9,51 +12,27 @@ import {
|
||||
set,
|
||||
} from 'date-fns';
|
||||
|
||||
const ARM_EMPLOYEES = [141339536453140480];
|
||||
const ARM_EMPLOYEES = ['141339536453140480'];
|
||||
const ARM_THUMBNAIL =
|
||||
'https://cdn.discordapp.com/attachments/724000975626698894/928379448301088868/unknown.png';
|
||||
const BAE_THUMBNAIL =
|
||||
'https://cdn.discordapp.com/attachments/724000975626698894/928380073965408306/Untitled-1.png';
|
||||
|
||||
// Adjust payday for weekends
|
||||
function adjustPayday(payday) {
|
||||
const dayOfWeek = getDay(payday);
|
||||
|
||||
if (dayOfWeek === 6) {
|
||||
// Saturday
|
||||
return subDays(payday, 1);
|
||||
} else if (dayOfWeek === 0) {
|
||||
// Sunday
|
||||
return subDays(payday, 2);
|
||||
}
|
||||
|
||||
return payday;
|
||||
}
|
||||
|
||||
// Calculate next payday based on the current date
|
||||
function calculateNextPayday(
|
||||
payday = 22,
|
||||
currentDate = new Date(),
|
||||
adjust = 0
|
||||
) {
|
||||
let theoreticalPayday = set(currentDate, { date: payday });
|
||||
let adjustedPayday = adjustPayday(theoreticalPayday);
|
||||
|
||||
if (adjustedPayday < currentDate) {
|
||||
theoreticalPayday = set(addDays(currentDate, adjust * 30), {
|
||||
date: payday,
|
||||
});
|
||||
adjustedPayday = adjustPayday(theoreticalPayday);
|
||||
}
|
||||
|
||||
return adjustedPayday;
|
||||
}
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('payday')
|
||||
.setDescription('Calculate the number of days until the next payday.');
|
||||
|
||||
async function execute(interaction) {
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Handle the payday command and reply with the number of days until the next payday.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const authorId = interaction.user.id;
|
||||
const embed = new EmbedBuilder().setTitle('Payday');
|
||||
|
||||
@@ -108,4 +87,46 @@ async function execute(interaction) {
|
||||
await interaction.reply({ embeds: [embed] });
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Adjust payday if it falls on a weekend.
|
||||
* @param payday The date of the payday.
|
||||
* @returns The adjusted payday if necessary.
|
||||
*/
|
||||
function adjustPayday(payday: Date): Date {
|
||||
const dayOfWeek = getDay(payday);
|
||||
|
||||
if (dayOfWeek === 6) {
|
||||
// Saturday
|
||||
return subDays(payday, 1);
|
||||
} else if (dayOfWeek === 0) {
|
||||
// Sunday
|
||||
return subDays(payday, 2);
|
||||
}
|
||||
|
||||
return payday;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the next payday based on the current date.
|
||||
* @param payday The day of the month for payday.
|
||||
* @param currentDate The current date to compare with.
|
||||
* @param adjust Number of months to adjust the payday.
|
||||
* @returns The next payday date.
|
||||
*/
|
||||
function calculateNextPayday(
|
||||
payday = 22,
|
||||
currentDate = new Date(),
|
||||
adjust = 0
|
||||
): Date {
|
||||
let theoreticalPayday = set(currentDate, { date: payday });
|
||||
let adjustedPayday = adjustPayday(theoreticalPayday);
|
||||
|
||||
if (adjustedPayday < currentDate) {
|
||||
theoreticalPayday = set(addDays(currentDate, adjust * 30), {
|
||||
date: payday,
|
||||
});
|
||||
adjustedPayday = adjustPayday(theoreticalPayday);
|
||||
}
|
||||
|
||||
return adjustedPayday;
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js';
|
||||
import {
|
||||
EmbedBuilder,
|
||||
SlashCommandBuilder,
|
||||
ChatInputCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import axios from 'axios';
|
||||
import config from '../config';
|
||||
|
||||
const API_URL = 'https://my-api.plantnet.org/v2/identify/all?api-key={apiKey}';
|
||||
const API_URL = `https://my-api.plantnet.org/v2/identify/all?api-key=${config.plantnetApiKey}`;
|
||||
const LEAF_THUMBNAIL =
|
||||
'https://cdn.discordapp.com/attachments/870024275556446328/1006249009201033287/monstera.png';
|
||||
|
||||
if (!process.env.PLANTNET_API_KEY) {
|
||||
throw new Error('PLANTNET_API_KEY is not set in the environment variables.');
|
||||
}
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('plant')
|
||||
.setDescription('Identify a plant by uploading an image.')
|
||||
.addAttachmentOption((option) =>
|
||||
@@ -19,39 +21,16 @@ const data = new SlashCommandBuilder()
|
||||
.setRequired(true)
|
||||
);
|
||||
|
||||
// Helper function to generate plant details
|
||||
function generatePlantDetail(commonName, scientificName, confidence) {
|
||||
let detail = '';
|
||||
|
||||
if (0.0 <= confidence && confidence < 0.25) {
|
||||
detail = `I'm really not sure, but I think that looks like a **${commonName}**?`;
|
||||
} else if (0.25 <= confidence && confidence < 0.5) {
|
||||
detail = `I think that looks like a **${commonName}**!`;
|
||||
} else if (0.5 <= confidence && confidence < 0.75) {
|
||||
detail = `That looks like a **${commonName}**!`;
|
||||
} else if (confidence >= 0.75) {
|
||||
detail = `That is a really cool **${commonName}**!`;
|
||||
}
|
||||
|
||||
const imageUrl = `https://www.google.com/search?q=${encodeURIComponent(
|
||||
commonName || scientificName
|
||||
)}&tbm=isch`;
|
||||
|
||||
detail += `\n\n**Scientific Name**: ${scientificName}`;
|
||||
detail += `\n\n**Images**: [More images](${imageUrl})`;
|
||||
detail += `\n\n**Confidence**: ${(confidence * 100).toFixed(3)}%`;
|
||||
|
||||
return detail;
|
||||
}
|
||||
|
||||
async function execute(interaction) {
|
||||
/**
|
||||
* Execute the plant identification command.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (!process.env.PLANTNET_API_KEY) {
|
||||
await interaction.editReply('The bot is missing the PlantNet API key.');
|
||||
return;
|
||||
}
|
||||
|
||||
const image = interaction.options.getAttachment('image');
|
||||
|
||||
try {
|
||||
@@ -62,10 +41,10 @@ async function execute(interaction) {
|
||||
|
||||
// API call to identify the plant
|
||||
const response = await axios.get(
|
||||
API_URL.replace('{apiKey}', process.env.PLANTNET_API_KEY),
|
||||
API_URL.replace('{apiKey}', process.env.PLANTNET_API_KEY as string),
|
||||
{
|
||||
params: {
|
||||
images: image.url,
|
||||
images: image?.url,
|
||||
organs: 'leaf',
|
||||
},
|
||||
timeout: 5000,
|
||||
@@ -99,7 +78,7 @@ async function execute(interaction) {
|
||||
|
||||
// Send the result to the user
|
||||
await interaction.editReply({ embeds: [embed] });
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error(error); // Log the error for debugging
|
||||
await interaction.editReply(
|
||||
'An error occurred when querying the PlantNet API.'
|
||||
@@ -107,4 +86,37 @@ async function execute(interaction) {
|
||||
}
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
/**
|
||||
* Generate plant details based on common name, scientific name, and confidence level.
|
||||
* @param commonName The common name of the plant.
|
||||
* @param scientificName The scientific name of the plant.
|
||||
* @param confidence The confidence score of the identification.
|
||||
* @returns A formatted string with the plant details.
|
||||
*/
|
||||
function generatePlantDetail(
|
||||
commonName: string,
|
||||
scientificName: string,
|
||||
confidence: number
|
||||
): string {
|
||||
let detail = '';
|
||||
|
||||
if (0.0 <= confidence && confidence < 0.25) {
|
||||
detail = `I'm really not sure, but I think that looks like a **${commonName}**?`;
|
||||
} else if (0.25 <= confidence && confidence < 0.5) {
|
||||
detail = `I think that looks like a **${commonName}**!`;
|
||||
} else if (0.5 <= confidence && confidence < 0.75) {
|
||||
detail = `That looks like a **${commonName}**!`;
|
||||
} else if (confidence >= 0.75) {
|
||||
detail = `That is a really cool **${commonName}**!`;
|
||||
}
|
||||
|
||||
const imageUrl = `https://www.google.com/search?q=${encodeURIComponent(
|
||||
commonName || scientificName
|
||||
)}&tbm=isch`;
|
||||
|
||||
detail += `\n\n**Scientific Name**: ${scientificName}`;
|
||||
detail += `\n\n**Images**: [More images](${imageUrl})`;
|
||||
detail += `\n\n**Confidence**: ${(confidence * 100).toFixed(3)}%`;
|
||||
|
||||
return detail;
|
||||
}
|
||||
22
src/commands/reminder.ts
Normal file
22
src/commands/reminder.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
|
||||
const REMINDER_IMAGE =
|
||||
'https://media.discordapp.net/attachments/506852356898422797/715690132883111996/Capture.PNG';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('reminder')
|
||||
.setDescription('Returns an image which must always be remembered.');
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Replies with an image that must always be remembered.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.reply(REMINDER_IMAGE);
|
||||
}
|
||||
22
src/commands/servertime.ts
Normal file
22
src/commands/servertime.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('servertime')
|
||||
.setDescription("Returns the server's current time.");
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Replies with the server's current time.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const now = new Date();
|
||||
const formattedTime = format(now, 'dd/MM/yyyy HH:mm:ss');
|
||||
await interaction.reply(`The server's current time is: ${formattedTime}`);
|
||||
}
|
||||
23
src/commands/taylor.ts
Normal file
23
src/commands/taylor.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
import taylorQuotes from './utils/constants/taylorQuotes.json';
|
||||
|
||||
// Initialise the command data.
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('taylor')
|
||||
.setDescription('Returns a Taylor Swift quote.');
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Returns a random Taylor Swift quote.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
const randomIndex = Math.floor(Math.random() * taylorQuotes.length);
|
||||
const response = taylorQuotes[randomIndex];
|
||||
|
||||
await interaction.reply(response);
|
||||
}
|
||||
22
src/commands/twentyTwenty.ts
Normal file
22
src/commands/twentyTwenty.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js';
|
||||
|
||||
const TWENTY_TWENTY_IMAGE =
|
||||
'https://cdn.discordapp.com/attachments/506852356898422797/765256712063025172/unknown.png';
|
||||
|
||||
// Initialize the command data
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName('twentytwenty')
|
||||
.setDescription('Returns a tweet from Boris, posted on 2 January 2020.');
|
||||
|
||||
console.log(`Loaded ${data.name} command.`);
|
||||
|
||||
/**
|
||||
* Sends an image of a tweet from Boris, posted on 2 January 2020.
|
||||
* @param interaction The interaction that triggered the command.
|
||||
* @returns A promise that resolves when the command is finished executing.
|
||||
*/
|
||||
export async function execute(
|
||||
interaction: ChatInputCommandInteraction
|
||||
): Promise<void> {
|
||||
await interaction.reply(TWENTY_TWENTY_IMAGE);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('countdown')
|
||||
.setDescription('Start a five second countdown.');
|
||||
|
||||
async function execute(interaction) {
|
||||
await interaction.reply({ content: 'Starting countdown...' });
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000)); // 2-second delay
|
||||
|
||||
for (let i = 5; i > 0; i--) {
|
||||
await interaction.editReply({ content: String(i) });
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000)); // 1-second delay between numbers
|
||||
}
|
||||
|
||||
await interaction.editReply({ content: '🎉 GO! 🎉' });
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('servertime')
|
||||
.setDescription("Returns the server's current time.");
|
||||
|
||||
async function execute(interaction) {
|
||||
const now = new Date();
|
||||
const formattedTime = format(now, 'dd/MM/yyyy HH:mm:ss');
|
||||
await interaction.reply(`The server's current time is: ${formattedTime}`);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
124
src/commands/utils/constants/kanyeQuotes.json
Normal file
124
src/commands/utils/constants/kanyeQuotes.json
Normal file
@@ -0,0 +1,124 @@
|
||||
[
|
||||
"2024.",
|
||||
"All you have to be is yourself.",
|
||||
"Believe in your flyness... conquer your shyness.",
|
||||
"Burn that Excel spreadsheet.",
|
||||
"Decentralize.",
|
||||
"Distraction is the enemy of vision.",
|
||||
"Everything you do in life stems from either fear or love.",
|
||||
"For me giving up is way harder than trying.",
|
||||
"For me, money is not my definition of success. Inspiring people is a definition of success.",
|
||||
"Fur pillows are hard to actually sleep on.",
|
||||
"George Bush doesn't care about black people.",
|
||||
"Have you ever thought you were in love with someone but then realized you were just staring in a mirror for 20 minutes?",
|
||||
"I care. I care about everything. Sometimes not giving a f#%k is caring the most.",
|
||||
"I feel calm but energized.",
|
||||
"I feel like I'm too busy writing history to read it.",
|
||||
"I feel like me and Taylor might still have sex.",
|
||||
"I give up drinking every week.",
|
||||
"I leave my emojis Bart Simpson color.",
|
||||
"I love sleep; it's my favorite.",
|
||||
"I make awesome decisions in bike stores!!!",
|
||||
"I really love my Tesla. I'm in the future. Thank you Elon.",
|
||||
"I still think I am the greatest.",
|
||||
"I think I do myself a disservice by comparing myself to Steve Jobs and Walt Disney and human beings that we've seen before. It should be more like Willy Wonka...and welcome to my chocolate factory.",
|
||||
"I want the world to be better! All I want is positive! All I want is dopeness!",
|
||||
"I wish I had a friend like me.",
|
||||
"I'd like to meet with Tim Cook. I got some ideas.",
|
||||
"I'll say things that are serious and put them in a joke form so people can enjoy them. We laugh to keep from crying.",
|
||||
"I'm a creative genius.",
|
||||
"I'm nice at ping pong.",
|
||||
"I'm the best.",
|
||||
"If I don't scream, if I don't say something then no one's going to say anything.",
|
||||
"If I got any cooler I would freeze to death.",
|
||||
"If you have the opportunity to play this game of life you need to appreciate every moment. a lot of people don't appreciate the moment until it's passed.",
|
||||
"Just stop lying about shit. Just stop lying.",
|
||||
"Keep squares out yo circle.",
|
||||
"Keep your nose out the sky, keep your heart to god, and keep your face to the rising sun.",
|
||||
"Let's be like water.",
|
||||
"Man... whatever happened to my antique fish tank?",
|
||||
"My dad got me a drone for Christmas.",
|
||||
"My greatest award is what I'm about to do.",
|
||||
"My greatest pain in life is that I will never be able to see myself perform live.",
|
||||
"One day I'm gon' marry a porn star.",
|
||||
"One of my favorite of many things about what the Trump hat represents to me is that people can't tell me what to do because I'm black.",
|
||||
"Only free thinkers.",
|
||||
"People always say that you can't please everybody. I think that's a cop-out. Why not attempt it? Cause think of all the people that you will please if you try.",
|
||||
"People always tell you 'Be humble. Be humble.' When was the last time someone told you to be amazing? Be great! Be awesome! Be awesome!",
|
||||
"People only get jealous when they care.",
|
||||
"Perhaps I should have been more like water today.",
|
||||
"Pulling up in the may bike.",
|
||||
"Shut the fuck up I will fucking laser you with alien fucking eyes and explode your fucking head.",
|
||||
"Sometimes I push the door close button on people running towards the elevator. I just need my own elevator sometimes. My sanctuary.",
|
||||
"Sometimes you have to get rid of everything.",
|
||||
"Style is genderless.",
|
||||
"The thought police want to suppress freedom of thought.",
|
||||
"The world is our family.",
|
||||
"The world is our office.",
|
||||
"Today is the best day ever and tomorrow's going to be even better.",
|
||||
"Truth is my goal. Controversy is my gym. I'll do a hundred reps of controversy for a 6 pack of truth.",
|
||||
"Tweeting is legal and also therapeutic.",
|
||||
"We all self-conscious. I'm just the first to admit it.",
|
||||
"We came into a broken world. And we're the cleanup crew.",
|
||||
"You can't look at a glass half full or empty if it's overflowing.",
|
||||
"I hate when I'm on a flight and I wake up with a water bottle next to me like oh great now I gotta be responsible for this water bottle.",
|
||||
"All the musicians will be free.",
|
||||
"Artists are founders.",
|
||||
"Buy property.",
|
||||
"Culture is the most powerful force in humanity under God.",
|
||||
"Empathy is the glue.",
|
||||
"I am one of the most famous people on the planet.",
|
||||
"I am running for President of the United States.",
|
||||
"I am the head of Adidas. I will bring Adidas and Puma back together and bring me and jay back together.",
|
||||
"I am Warhol. I am the No. 1 most impactful artist of our generation. I am Shakespeare in the flesh.",
|
||||
"I channel Will Ferrell when I'm at the daddy daughter dances.",
|
||||
"I don't wanna see no woke tweets or hear no woke raps ... it's show time ... it's a whole different energy right now.",
|
||||
"I hear people say this person is cool and this person is not cool. People are cool. Man has never invented anything as awesome as a an actual person but sometimes we value the objects we create over life itself.",
|
||||
"I honestly need all my Royeres to be museum quality... if I see a fake Royere Ima have to Rick James your couch.",
|
||||
"I love UZI. I be saying the same thing about Steve Jobs. I be feeling just like UZI.",
|
||||
"I need an army of angels to cover me while I pull this sword out of the stone.",
|
||||
"I spoke to Dave Chapelle for two hours this morning. He is our modern day Socrates.",
|
||||
"I was just speaking with someone that told me their life story and they used to be homeless.",
|
||||
"I watch Bladerunner on repeat.",
|
||||
"I'm giving all Good music artists back the 50% share I have of their masters.",
|
||||
"I'm going to personally see to it that Taylor Swift gets her masters back. Scooter is a close family friend.",
|
||||
"I'm the new Moses.",
|
||||
"Life is the ultimate gift.",
|
||||
"Ma$e is one of my favorite rappers and I based a lot of my flows off of him.",
|
||||
"Manga all day.",
|
||||
"My first pillar when I'm on the board of adidas will be an adidas Nike collaboration to support community growth.",
|
||||
"My mama was a' English teacher. I know how to use correct English but sometimes I just don't feel like it aaaand I ain't got to.",
|
||||
"My memories are from the future.",
|
||||
"My mother in law Kris Jenner ... makes the best music playlist.",
|
||||
"People say it's enough and I got my point across ... the point isn't across until we cross the point.",
|
||||
"People tried to talk me out of running for President. Never let weak controlling people kill your spirit.",
|
||||
"So many of us need so much less than we have especially when so many of us are in need.",
|
||||
"Speak God's truth to power.",
|
||||
"The media tries to kill our heroes one at a time.",
|
||||
"The world needs more Joy... this idea is super fresh.",
|
||||
"There are 5 main pillars in a professional musicians business - Recording, Publishing, Touring, Merchandise & Name and likeness.",
|
||||
"There are people sleeping in parking lots.",
|
||||
"There's a crying need for civility across the board. We need to and will come together in the name of Jesus.",
|
||||
"There's so many lonely emojis man.",
|
||||
"Trust me ... I won't stop.",
|
||||
"Two years ago we had 50 million people subscribed to music streaming services around the world. Today we have 400 million.",
|
||||
"We are here to complete the revolution. We are building the future.",
|
||||
"We as a people will heal. We will insure the well being of each other.",
|
||||
"We have to evolve.",
|
||||
"We must and will cure homelessness and hunger. We have the capability as a species.",
|
||||
"We must form a union. We must unify.",
|
||||
"We used to diss Michael Jackson the media made us call him crazy ... then they killed him.",
|
||||
"We will be recognized.",
|
||||
"We will change the paradigm.",
|
||||
"We will cure hunger.",
|
||||
"We will heal. We will cure.",
|
||||
"We're going to move the entire music industry into the 21st Century.",
|
||||
"We've gotten comfortable with not having what we deserve.",
|
||||
"Who made up the term major label in the first place???",
|
||||
"Winning is the only option.",
|
||||
"For me to say I wasn't a genius I'd just be lying to you and to myself.",
|
||||
"I've known my mom since I was zero years old. She is quite dope.",
|
||||
"I don't expect to be understood at all.",
|
||||
"I'm on the pursuit of awesomeness, excellence is the bare minimum.",
|
||||
"You basically can say anything to someone on an email or text as long as you put LOL at the end."
|
||||
]
|
||||
22
src/commands/utils/constants/magicEightBallResponses.json
Normal file
22
src/commands/utils/constants/magicEightBallResponses.json
Normal file
@@ -0,0 +1,22 @@
|
||||
[
|
||||
"As I see it, yes.",
|
||||
"Ask again later.",
|
||||
"Better not tell you now.",
|
||||
"Cannot predict now.",
|
||||
"Concentrate and ask again.",
|
||||
"Don't count on it.",
|
||||
"It is certain.",
|
||||
"It is decidedly so.",
|
||||
"Most likely.",
|
||||
"My reply is no.",
|
||||
"My sources say no.",
|
||||
"Outlook not so good.",
|
||||
"Outlook good.",
|
||||
"Reply hazy, try again.",
|
||||
"Signs point to yes.",
|
||||
"Very doubtful.",
|
||||
"Without a doubt.",
|
||||
"Yes.",
|
||||
"Yes - definitely.",
|
||||
"You may rely on it."
|
||||
]
|
||||
@@ -1,142 +1,140 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
const TAYLOR_QUOTES = [
|
||||
[
|
||||
"I don't know what I want, so don't ask me, 'cause I'm still trying to figure it out.",
|
||||
'When you think Tim McGraw, I hope you think of me.',
|
||||
'So watch me strike a match on all my wasted time.',
|
||||
"When you think Tim McGraw, I hope you think of me.",
|
||||
"So watch me strike a match on all my wasted time.",
|
||||
"I'll be strong, I'll be wrong, oh but life goes on…",
|
||||
'And when you take, you take the very best of me.',
|
||||
"And when you take, you take the very best of me.",
|
||||
"But no one notices until it's too late to do anything.",
|
||||
"Our song is the slamming screen door, sneakin' out late, tapping on your window.",
|
||||
"And I don't know why, but with you I'd dance in a storm in my best dress, fearless.",
|
||||
"But in your life, you'll do things greater than dating the boy on the football team…But I didn't know it at fifteen.",
|
||||
"I've found time can heal most anything and you just might find who you're supposed to be.",
|
||||
"Romeo, save me. They're trying to tell me how to feel. This love is difficult but it's real.",
|
||||
'Why are people always leaving? I think you and I should stay the same.',
|
||||
"Why are people always leaving? I think you and I should stay the same.",
|
||||
"My mistake, I didn't know to be in love you had to fight to have the upper hand.",
|
||||
'This is a big world, that was a small town there in my rear view mirror disappearing now.',
|
||||
"This is a big world, that was a small town there in my rear view mirror disappearing now.",
|
||||
"You've got a smile that could light up this whole town.",
|
||||
"And we know it's never simple, never easy. Never a clean break, no one here to save me.",
|
||||
'You took a swing, I took it hard. And down here from the ground I see who you are.',
|
||||
"You took a swing, I took it hard. And down here from the ground I see who you are.",
|
||||
"All this time I was wasting, hoping you would come around… I've been giving out chances every time and all you do is let me down.",
|
||||
"And then you feel so low you can't feel nothing at all.",
|
||||
"It rains when you're here and it rains when you're gone.",
|
||||
'These walls that they put up to hold us back will fall down…',
|
||||
"These walls that they put up to hold us back will fall down…",
|
||||
"My mind forgets to remind me you're a bad idea.",
|
||||
"It turns out freedom ain't nothing but missing you.",
|
||||
"She floats down the aisle like a pageant queen, but I know you wish it was me… don't you?",
|
||||
'I lived in your chess game, but you changed the rules every day.',
|
||||
"I lived in your chess game, but you changed the rules every day.",
|
||||
"I'm shining like fireworks over your sad, empty town.",
|
||||
"Someday I'll be living in a big, old city and all you're ever gonna be is mean.",
|
||||
"I'd tell you I miss you, but I don't know how, I've never heard silence quite this loud.",
|
||||
'This is looking like a contest of who can act like they care less. But I liked it better when you were on my side.',
|
||||
"This is looking like a contest of who can act like they care less. But I liked it better when you were on my side.",
|
||||
"And don't lose the way that you dance around in your pj's getting ready for school.",
|
||||
"This night is sparkling, don't you let it go. I'm wonderstruck, blushing all the way home.",
|
||||
'2AM, who do you love?',
|
||||
"2AM, who do you love?",
|
||||
"Your string of lights is still bright to me… Who you are is not where you've been.",
|
||||
'Today is never too late to be brand new.',
|
||||
"Today is never too late to be brand new.",
|
||||
"You and I walk a fragile line; I have known it all this time. But I never thought I'd live to see it break.",
|
||||
"I don't know how to be something you miss.",
|
||||
'Bring on all the pretenders. One day, we will be remembered.',
|
||||
"Bring on all the pretenders. One day, we will be remembered.",
|
||||
"So don't you worry your pretty, little mind, people throw rocks at things that shine.",
|
||||
"We are alone with our changing minds. We fall in love 'til it hurts or bleeds or fades in time.",
|
||||
'Love is a ruthless game unless you play it good and right.',
|
||||
"Love is a ruthless game unless you play it good and right.",
|
||||
"He's long gone when he's next to me and I realize the blame is on me.",
|
||||
"No apologies. He'll never see you cry. Pretends he doesn't know that he's the reason why.",
|
||||
'The saddest fear comes creeping in - that you never loved me or her, or anyone, or anything...',
|
||||
"The saddest fear comes creeping in - that you never loved me or her, or anyone, or anything...",
|
||||
"…That magic's not here no more. And I might be OK, but I'm not fine at all.",
|
||||
"And your mother's telling stories about you on a tee ball team. You taught me 'bout your past, thinking your future was me.",
|
||||
'I forget about you long enough to forget why I needed to...',
|
||||
"I forget about you long enough to forget why I needed to...",
|
||||
"Maybe we got lost in translation, maybe I asked for too much. But maybe this thing was a masterpiece 'til you tore it all up. Running scared, I was there, I remember it all too well.",
|
||||
'You call me up again just to break me like a promise, so casually cruel in the name of being honest.',
|
||||
"You call me up again just to break me like a promise, so casually cruel in the name of being honest.",
|
||||
"Time won't fly, it's like I'm paralyzed by it. I'd like to be my old self again, but I'm still trying to find it.",
|
||||
"Cause there we are again, when I loved you so, back before you lost the one, real thing you've ever known.",
|
||||
"Now you mail back my things and I walk home alone, but you keep my old scarf from that very first week, 'cause it reminds you of innocence and it smells like me.",
|
||||
"Stay, and I'll be loving you for quite some time. No one else is gonna love me when I get mad.",
|
||||
"We're happy, free, confused, and lonely at the same time. It's miserable and magical.",
|
||||
"I wish I could run to you. And I hope you know that every time I don't I almost do.",
|
||||
'You wear your best apology, but I was there to watch you leave.',
|
||||
'But sometimes I wonder how you think about it now.',
|
||||
"You wear your best apology, but I was there to watch you leave.",
|
||||
"But sometimes I wonder how you think about it now.",
|
||||
"But I don't wanna dance if I'm not dancing with you.",
|
||||
"Words, how little they mean when you're a little too late.",
|
||||
"And they tell you that you're lucky, but you're so confused, 'cause you don't feel pretty, you just feel used.",
|
||||
"I've been spending the last eight months thinking all love ever does is break and burn and end...",
|
||||
"And what do you do when the one who means the most to you is the one who didn't show?",
|
||||
"Your close friends always seem to know when there's something really wrong",
|
||||
'You called me later and said, "I\'m sorry I didn\'t make it". And I said, "I\'m sorry, too".',
|
||||
'Loving him is like driving a new Maserati down a dead-end street - faster than the wind, passionate as sin, ending so suddenly.',
|
||||
'The lights are so bright, but they never blind me.',
|
||||
"You called me later and said, \"I'm sorry I didn't make it\". And I said, \"I'm sorry, too\".",
|
||||
"Loving him is like driving a new Maserati down a dead-end street - faster than the wind, passionate as sin, ending so suddenly.",
|
||||
"The lights are so bright, but they never blind me.",
|
||||
"Love's a game, wanna play?",
|
||||
"So it's gonna be forever or it's gonna go down in flames.",
|
||||
"But you'll come back each time you leave 'cause darling, I'm a nightmare dressed like a daydream.",
|
||||
"When we go crashing down, we come back every time 'cause we never go out of style.",
|
||||
'I got that red lip, classic thing that you like.',
|
||||
'The rest of the world was black and white, but we were in screaming color.',
|
||||
'The more I think about it now, the less I know, all I know is that you drove us off the road.',
|
||||
'People like you always want back the love they pushed aside, but people like me are gone forever when you say goodbye.',
|
||||
"I got that red lip, classic thing that you like.",
|
||||
"The rest of the world was black and white, but we were in screaming color.",
|
||||
"The more I think about it now, the less I know, all I know is that you drove us off the road.",
|
||||
"People like you always want back the love they pushed aside, but people like me are gone forever when you say goodbye.",
|
||||
"Why'd you have to go and lock me out when I let you in?",
|
||||
"While you've been getting down and out about the liars and the dirty, dirty cheats of the world… You could've been getting down to this sick beat.",
|
||||
"We're a crooked love in a straight line down.",
|
||||
'And I wish you knew that I miss you too much to be mad anymore.',
|
||||
'You give me everything and nothing.',
|
||||
'Makes you wanna run and hide, but it made us turn right back around.',
|
||||
"And I wish you knew that I miss you too much to be mad anymore.",
|
||||
"You give me everything and nothing.",
|
||||
"Makes you wanna run and hide, but it made us turn right back around.",
|
||||
"Band-aids don't fix bullet holes. You say sorry just for show.",
|
||||
'Someday when you leave me, I bet these memories follow you around.',
|
||||
"Someday when you leave me, I bet these memories follow you around.",
|
||||
"When you're young, you just run, but you come back to what you need.",
|
||||
'This love left a permanent mark.',
|
||||
'Your kiss, my cheek; I watch you leave. Your smile, my ghost; I fall to my knees.',
|
||||
"This love left a permanent mark.",
|
||||
"Your kiss, my cheek; I watch you leave. Your smile, my ghost; I fall to my knees.",
|
||||
"It was months and months of back and forth, you're still all over me like a wine-stained dress I can't wear anymore.",
|
||||
"When I was drowning that's when I could finally breathe.",
|
||||
"Just because you're clean, don't mean you don't miss it.",
|
||||
"Didn't it all seem new and exciting? …It's all fun and games 'til somebody loses their mind.",
|
||||
'You search the world for something else to make you feel like what we had. And in the end in wonderland, we both went mad.',
|
||||
'Heartbreak is the national anthem, we sing it proudly.',
|
||||
"You search the world for something else to make you feel like what we had. And in the end in wonderland, we both went mad.",
|
||||
"Heartbreak is the national anthem, we sing it proudly.",
|
||||
"They'll take their shots, but we are bulletproof.",
|
||||
'So I punched a hole in the roof; let the flood carry away all my pictures of you.',
|
||||
'When all you wanted was to be wanted; wish you could go back and tell yourself what you know now.',
|
||||
"So I punched a hole in the roof; let the flood carry away all my pictures of you.",
|
||||
"When all you wanted was to be wanted; wish you could go back and tell yourself what you know now.",
|
||||
"32 and still growing up now. Who you are is not what you did. You're still an innocent.",
|
||||
"We play dumb but we know exactly what we're doing.",
|
||||
"Please don't ever become a stranger whose laugh I could recognize anywhere.",
|
||||
'Can we always be this close forever and ever?',
|
||||
"Can we always be this close forever and ever?",
|
||||
"I'm only seventeen. I don't know anything but I know I miss you.",
|
||||
'I was walking home on broken cobblestones just thinking of you, when she pulled up like a figment of my worst intentions.',
|
||||
'You play stupid games, you win stupid prizes.',
|
||||
'I had a marvelous time ruining everything.',
|
||||
"I was walking home on broken cobblestones just thinking of you, when she pulled up like a figment of my worst intentions.",
|
||||
"You play stupid games, you win stupid prizes.",
|
||||
"I had a marvelous time ruining everything.",
|
||||
"Untouchable, burning brighter than the sun, and when you're close I feel like coming undone.",
|
||||
'I could build a castle out of all the bricks they threw at me.',
|
||||
'Cold was the steel of my axe to grind for the boys who broke my heart. Now I send their babies presents.',
|
||||
'Back when you fit in my poems like a perfect rhyme.',
|
||||
"I could build a castle out of all the bricks they threw at me.",
|
||||
"Cold was the steel of my axe to grind for the boys who broke my heart. Now I send their babies presents.",
|
||||
"Back when you fit in my poems like a perfect rhyme.",
|
||||
"I once believed love would be burning red... but it's golden.",
|
||||
'The monsters turned out to be just trees, when the sun came up you were looking at me.',
|
||||
"The monsters turned out to be just trees, when the sun came up you were looking at me.",
|
||||
"I can't decide if it's a choice: getting swept away?",
|
||||
'They told me all of my cages were mental, so I got wasted like all my potential.',
|
||||
"They told me all of my cages were mental, so I got wasted like all my potential.",
|
||||
"I don't like that falling feels like flying till the bone crush.",
|
||||
'I persist and resist the temptation to ask you: "If one thing had been different, would everything be different today?"',
|
||||
'When you are young they assume you know nothing.',
|
||||
"I persist and resist the temptation to ask you: \"If one thing had been different, would everything be different today?\"",
|
||||
"When you are young they assume you know nothing.",
|
||||
"You drew stars around my scars, but now I'm bleeding.",
|
||||
'You wear the same jewels that I gave you, as you bury me.',
|
||||
"You wear the same jewels that I gave you, as you bury me.",
|
||||
"We gather stones, never knowing what they'll mean - some to throw, some to make a diamond ring.",
|
||||
'Bold was the waitress on our three-year trip... Getting lunch down by the Lakes, she said I looked like an American singer.',
|
||||
'One single thread of gold tied me to you.',
|
||||
"Bold was the waitress on our three-year trip... Getting lunch down by the Lakes, she said I looked like an American singer.",
|
||||
"One single thread of gold tied me to you.",
|
||||
"I swear I don't love the drama, it loves me.",
|
||||
"I bury hatchets, but I keep maps of where I put 'em.",
|
||||
"Love made me crazy, if it doesn't, you ain't doin' it right.",
|
||||
"My name is whatever you decide, and I'm just gonna call you mine.",
|
||||
"Handsome, you're a mansion with a view.",
|
||||
'Sometimes I wonder when you sleep, are you ever dreaming of me?',
|
||||
'The world goes on another day, another drama. But not for me, all I think about is karma.',
|
||||
'You asked me for a place to sleep, locked me out and threw a feast.',
|
||||
"Sometimes I wonder when you sleep, are you ever dreaming of me?",
|
||||
"The world goes on another day, another drama. But not for me, all I think about is karma.",
|
||||
"You asked me for a place to sleep, locked me out and threw a feast.",
|
||||
"You know I'm not a bad girl, but I do bad things with you.",
|
||||
"You did a number on me but, honestly, baby, who's counting?",
|
||||
'Ocean blue eyes looking in mine. I feel like I might sink and drown and die.',
|
||||
"Ocean blue eyes looking in mine. I feel like I might sink and drown and die.",
|
||||
"Your love is a secret I'm hoping, dreaming, dying to keep.",
|
||||
'Is this the end of all the endings? My broken bones are mending.',
|
||||
'I loved you in spite of deep fears that the world would divide us.',
|
||||
"Is this the end of all the endings? My broken bones are mending.",
|
||||
"I loved you in spite of deep fears that the world would divide us.",
|
||||
"Say that we got it! I'm a mess, but I'm the mess that you wanted!",
|
||||
'I brought a knife to a gunfight.',
|
||||
'He built a fire just to keep me warm.',
|
||||
'I want to wear his initial on a chain round my neck, not because he owns me, but cause he really knows me, which is more than they can say.',
|
||||
'Holding my breath, slowly, I said "You don\'t need to save me, but would you run away with me?"',
|
||||
"I brought a knife to a gunfight.",
|
||||
"He built a fire just to keep me warm.",
|
||||
"I want to wear his initial on a chain round my neck, not because he owns me, but cause he really knows me, which is more than they can say.",
|
||||
"Holding my breath, slowly, I said \"You don't need to save me, but would you run away with me?\"",
|
||||
"Would've been right there, front row even if nobody came to your show.",
|
||||
"I'm always waiting for you to be waiting below.",
|
||||
"I don't wanna keep secrets just to keep you.",
|
||||
@@ -147,38 +145,25 @@ const TAYLOR_QUOTES = [
|
||||
"I'll never let you go 'cause I know this is a fight that someday we're gonna win.",
|
||||
"I'm with you even if it makes me blue.",
|
||||
"Without all the exes, fights, and flaws, we wouldn't be standing here so tall.",
|
||||
'We were a fresh page on the desk, filling in the blanks as we go.',
|
||||
'We were in the backseat drunk on something stronger than the drinks in the bar.',
|
||||
'If the story is over, why am I still writing pages?',
|
||||
"We were a fresh page on the desk, filling in the blanks as we go.",
|
||||
"We were in the backseat drunk on something stronger than the drinks in the bar.",
|
||||
"If the story is over, why am I still writing pages?",
|
||||
"I ask the traffic lights if it will be alright, they say I don't know.",
|
||||
"They say home is where the heart is, but that's not where mine lives.",
|
||||
'I pinned your hands behind your back. Thought I had reason to attack, but no.',
|
||||
"I pinned your hands behind your back. Thought I had reason to attack, but no.",
|
||||
"Fighting with a true love is boxing with no gloves... Chemistry 'til it blows up, 'til there's no us.",
|
||||
"And I can't talk to you when you're like this, staring out the window like I'm not your favorite town.",
|
||||
'They say the road gets hard and you get lost.',
|
||||
"They say the road gets hard and you get lost.",
|
||||
"Remember how I said I'd die for you?",
|
||||
"I come back stronger than a '90s trend.",
|
||||
'"This dorm was once a madhouse." I made a joke: "Well, it\'s made for me."',
|
||||
"\"This dorm was once a madhouse.\" I made a joke: \"Well, it's made for me.\"",
|
||||
"Sometimes you just don't know the answer 'til someone's on their knees and asks you.",
|
||||
"I can't dare to dream about you anymore.",
|
||||
'I parked my car right between the Methodist and the school that used to be ours.',
|
||||
"I parked my car right between the Methodist and the school that used to be ours.",
|
||||
"I'll go back to L.A. and the so-called friends who'll write books about me if I ever make it and wonder about the only soul who can tell which smiles I'm fakin'.",
|
||||
'What would you do if I break free and leave us in ruins, took this dagger in me and removed it, gain the weight of you then loose it?',
|
||||
'Your nemesis will defeat themselves before you get the chance to swing.',
|
||||
'My waves meet your shore ever and evermore.',
|
||||
'I replay my footsteps on each stepping stone, trying to find the one where I went wrong.',
|
||||
"He can't see the smile I'm faking and my heart's not breaking 'cause I'm not feeling anything at all.",
|
||||
];
|
||||
|
||||
const data = new SlashCommandBuilder()
|
||||
.setName('taylor')
|
||||
.setDescription('Returns a random Taylor Swift quote.');
|
||||
|
||||
async function execute(interaction) {
|
||||
const randomIndex = Math.floor(Math.random() * TAYLOR_QUOTES.length);
|
||||
const quote = TAYLOR_QUOTES[randomIndex];
|
||||
|
||||
await interaction.reply(quote);
|
||||
}
|
||||
|
||||
export default { data, execute };
|
||||
"What would you do if I break free and leave us in ruins, took this dagger in me and removed it, gain the weight of you then loose it?",
|
||||
"Your nemesis will defeat themselves before you get the chance to swing.",
|
||||
"My waves meet your shore ever and evermore.",
|
||||
"I replay my footsteps on each stepping stone, trying to find the one where I went wrong.",
|
||||
"He can't see the smile I'm faking and my heart's not breaking 'cause I'm not feeling anything at all."
|
||||
]
|
||||
91
src/commands/utils/db/game.ts
Normal file
91
src/commands/utils/db/game.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
MongoClient,
|
||||
Db,
|
||||
Collection,
|
||||
Document,
|
||||
UpdateResult,
|
||||
DeleteResult,
|
||||
} from 'mongodb';
|
||||
import config from '../../../config';
|
||||
|
||||
let client: MongoClient;
|
||||
let database: Db;
|
||||
let collection: Collection<Document>;
|
||||
|
||||
async function initializeDbConnection() {
|
||||
if (!client) {
|
||||
client = new MongoClient(config.mongodbUri);
|
||||
await client.connect();
|
||||
database = client.db('butler_db');
|
||||
collection = database.collection('GameFeatures');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of game names from the database.
|
||||
*
|
||||
* @returns An array of game objects containing game names.
|
||||
*/
|
||||
export async function listGameNames(): Promise<any[]> {
|
||||
await initializeDbConnection();
|
||||
return collection.find({}, { projection: { game: 1 } }).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific game by its name from the database.
|
||||
*
|
||||
* @param game - The name of the game to retrieve.
|
||||
* @returns The game object if found, or null if not found.
|
||||
*/
|
||||
export async function getGame(game: string): Promise<any | null> {
|
||||
await initializeDbConnection();
|
||||
return collection.findOne({ game });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a key-value pair for a specific game in the database.
|
||||
* If the game does not exist, it will be created.
|
||||
*
|
||||
* @param game - The name of the game to update or create.
|
||||
* @param key - The key to set or update in the game object.
|
||||
* @param value - The value to set for the specified key.
|
||||
* @returns The result of the update operation.
|
||||
*/
|
||||
export async function setGame(
|
||||
game: string,
|
||||
key: string,
|
||||
value: any
|
||||
): Promise<UpdateResult> {
|
||||
await initializeDbConnection();
|
||||
return collection.updateOne(
|
||||
{ game },
|
||||
{ $set: { game, [key]: value } },
|
||||
{ upsert: true }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a game from the database by its name.
|
||||
*
|
||||
* @param game - The name of the game to delete.
|
||||
* @returns The result of the delete operation.
|
||||
*/
|
||||
export async function deleteGame(game: string): Promise<DeleteResult> {
|
||||
await initializeDbConnection();
|
||||
return collection.deleteOne({ game });
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific field from a game object in the database.
|
||||
*
|
||||
* @param game - The name of the game to update.
|
||||
* @param key - The field key to remove from the game object.
|
||||
* @returns The result of the update operation.
|
||||
*/
|
||||
export async function deleteField(
|
||||
game: string,
|
||||
key: string
|
||||
): Promise<UpdateResult> {
|
||||
await initializeDbConnection();
|
||||
return collection.updateOne({ game }, { $unset: { [key]: '' } });
|
||||
}
|
||||
81
src/commands/utils/music/trackProvider.ts
Normal file
81
src/commands/utils/music/trackProvider.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import axios from 'axios';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
/**
|
||||
* Enum representing the supported music providers.
|
||||
*/
|
||||
export enum MusicProvider {
|
||||
YouTube = 'youtube',
|
||||
Spotify = 'spotify',
|
||||
Local = 'local',
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface representing a track's metadata.
|
||||
*/
|
||||
export interface Track {
|
||||
provider: MusicProvider;
|
||||
id: string;
|
||||
title: string;
|
||||
artist: string;
|
||||
imageUrl: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches track information based on the provider and query.
|
||||
*
|
||||
* @param provider - The music provider (YouTube, Spotify, Local).
|
||||
* @param query - The search query for the track.
|
||||
* @returns A promise that resolves to a Track object.
|
||||
*/
|
||||
export async function fetchTrack(
|
||||
provider: MusicProvider,
|
||||
query: string
|
||||
): Promise<Track | null> {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`https://music.3t.network/${provider}/${provider === MusicProvider.Local ? 'search' : 'track'}`,
|
||||
{
|
||||
params: { query },
|
||||
}
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
|
||||
if (data && data.id) {
|
||||
return {
|
||||
provider,
|
||||
id: data.id,
|
||||
title: data.title,
|
||||
artist: data.artist || data.channel,
|
||||
imageUrl: data.imageUrl,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching track from ${provider}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the audio file from the download endpoint based on the provider and track ID.
|
||||
*
|
||||
* @param track - The track to stream.
|
||||
* @returns A Readable stream of the audio.
|
||||
*/
|
||||
export function streamAudio(track: Track): Readable {
|
||||
const downloadUrl =
|
||||
track.provider === MusicProvider.YouTube
|
||||
? `https://music.3t.network/youtube/video/${track.id}/download`
|
||||
: track.provider === MusicProvider.Spotify
|
||||
? `https://music.3t.network/spotify/track/${track.id}/download`
|
||||
: `https://music.3t.network/local/${track.id}/download`;
|
||||
|
||||
return axios({
|
||||
method: 'get',
|
||||
url: downloadUrl,
|
||||
responseType: 'stream',
|
||||
}).then((response) => response.data as Readable);
|
||||
}
|
||||
33
src/config.ts
Normal file
33
src/config.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config(); // Load variables from .env file
|
||||
|
||||
interface Config {
|
||||
discordApplicationId: string;
|
||||
discordApiKey: string;
|
||||
giphyApiKey: string;
|
||||
plantnetApiKey: string;
|
||||
omdbApiKey: string;
|
||||
replicateApiKey: string;
|
||||
mongodbUri: string;
|
||||
}
|
||||
|
||||
const getEnv = (key: string, required = true): string | undefined => {
|
||||
const value = process.env[key];
|
||||
if (!value && required) {
|
||||
throw new Error(`${key} is not set in the environment variables.`);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const config: Config = {
|
||||
discordApplicationId: getEnv('DISCORD_APPLICATION_ID') as string,
|
||||
discordApiKey: getEnv('DISCORD_API_KEY') as string,
|
||||
giphyApiKey: getEnv('GIPHY_API_KEY') as string,
|
||||
plantnetApiKey: getEnv('PLANTNET_API_KEY') as string,
|
||||
omdbApiKey: getEnv('OMDB_API_KEY') as string,
|
||||
replicateApiKey: getEnv('REPLICATE_API_KEY') as string,
|
||||
mongodbUri: getEnv('MONGODB_URI') as string,
|
||||
};
|
||||
|
||||
export default config;
|
||||
46
src/index.js
46
src/index.js
@@ -1,46 +0,0 @@
|
||||
import 'dotenv/config';
|
||||
import { Client, Collection, Events, GatewayIntentBits } from 'discord.js';
|
||||
import { loadCommandModules } from './utilities/commandModules.js';
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
// Load all command modules and set them in the client.
|
||||
client.commands = new Collection();
|
||||
const commandModules = await loadCommandModules();
|
||||
commandModules.forEach((module) => {
|
||||
client.commands.set(module.data.name, module);
|
||||
});
|
||||
|
||||
// Register the event listener for command interactions.
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const command = client.commands.get(interaction.commandName);
|
||||
if (!command) {
|
||||
console.warn(`Command ${interaction.commandName} not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await command.execute(interaction);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
await interaction.followUp({
|
||||
content: 'There was an error while executing this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({
|
||||
content: 'There was an error while executing this command!',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.once(Events.ClientReady, (readyClient) => {
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.login(process.env.DISCORD_API_KEY);
|
||||
35
src/index.ts
Normal file
35
src/index.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'dotenv/config';
|
||||
import {
|
||||
Client,
|
||||
Collection,
|
||||
Events,
|
||||
GatewayIntentBits,
|
||||
Interaction,
|
||||
} from 'discord.js';
|
||||
import { commands } from './commands';
|
||||
|
||||
// Define an extended version of the Client interface to include commands
|
||||
interface ExtendedClient extends Client {
|
||||
commands: Collection<string, any>;
|
||||
}
|
||||
|
||||
const client: ExtendedClient = new Client({
|
||||
intents: [GatewayIntentBits.Guilds],
|
||||
}) as ExtendedClient;
|
||||
|
||||
// Register the event listener for command interactions.
|
||||
client.on(Events.InteractionCreate, async (interaction: Interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const { commandName } = interaction;
|
||||
|
||||
if (commands[commandName as keyof typeof commands]) {
|
||||
commands[commandName as keyof typeof commands].execute(interaction);
|
||||
}
|
||||
});
|
||||
|
||||
client.once(Events.ClientReady, (readyClient) => {
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.login(process.env.DISCORD_API_KEY);
|
||||
@@ -1,28 +0,0 @@
|
||||
import 'dotenv/config';
|
||||
import { REST, Routes } from 'discord.js';
|
||||
import { loadCommandModules } from './utilities/commandModules.js';
|
||||
|
||||
// Register all slash commands, globally across all Guilds.
|
||||
const commandModules = await loadCommandModules();
|
||||
const commands = commandModules.map((commandModule) =>
|
||||
commandModule.data.toJSON()
|
||||
);
|
||||
|
||||
const rest = new REST().setToken(process.env.DISCORD_API_KEY);
|
||||
|
||||
try {
|
||||
console.log('Started refreshing application (/) commands.');
|
||||
|
||||
// Refresh all slash commands globally.
|
||||
const data = await rest.put(
|
||||
Routes.applicationCommands(process.env.DISCORD_APPLICATION_ID),
|
||||
{ body: commands }
|
||||
);
|
||||
|
||||
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
|
||||
// Exit the process.
|
||||
process.exit();
|
||||
} catch (error) {
|
||||
// And of course, make sure you catch and log any errors!
|
||||
console.error(error);
|
||||
}
|
||||
25
src/register-slash-commands.ts
Normal file
25
src/register-slash-commands.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
import { ApplicationCommand } from 'discord.js';
|
||||
|
||||
/**
|
||||
* Get all command modules from the commands directory.
|
||||
* @returns {Promise<string[]>} The file paths of all command modules.
|
||||
*/
|
||||
async function getCommandModulePaths() {
|
||||
return await glob(path.join(process.cwd(), 'src/commands/**/*.js'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single command module.
|
||||
* @param {string} modulePath The path to the command module.
|
||||
* @returns {Promise<ApplicationCommand>} The loaded command module.
|
||||
*/
|
||||
async function loadCommandModule(modulePath) {
|
||||
try {
|
||||
const module = await import(path.resolve(modulePath));
|
||||
const commandModule = module.default;
|
||||
|
||||
if (!commandModule.data || !commandModule.execute) {
|
||||
console.warn(`Invalid command module at ${modulePath}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.info(`Loaded command module: ${commandModule.data.name}`);
|
||||
return commandModule;
|
||||
} catch (error) {
|
||||
console.error(`Error loading module at ${modulePath}.`, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all command modules.
|
||||
* @returns {Promise<ApplicationCommand[]>} The loaded command modules.
|
||||
*/
|
||||
export async function loadCommandModules() {
|
||||
const commandModulePaths = await getCommandModulePaths();
|
||||
const commandModules = await Promise.all(
|
||||
commandModulePaths.map(loadCommandModule)
|
||||
);
|
||||
|
||||
return commandModules.filter((module) => module);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import { MongoClient } from 'mongodb';
|
||||
|
||||
if (!process.env.MONGODB_URI) {
|
||||
throw new Error('MONGODB_URI is not set in the environment variables.');
|
||||
}
|
||||
|
||||
const client = new MongoClient(process.env.MONGODB_URI);
|
||||
await client.connect();
|
||||
|
||||
const database = client.db('butler_db');
|
||||
const collection = database.collection('GameFeatures');
|
||||
|
||||
export async function listGameNames() {
|
||||
return collection.find({}, { projection: { game: 1 } }).toArray();
|
||||
}
|
||||
|
||||
export async function getGame(game) {
|
||||
return collection.findOne({ game });
|
||||
}
|
||||
|
||||
export async function setGame(game, key, value) {
|
||||
// If game is not found, create a new document with game field set to game, and key field set to value.
|
||||
// Overwrite the value of the key field if it already exists.
|
||||
return collection.updateOne(
|
||||
{ game },
|
||||
{ $set: { game, [key]: value } },
|
||||
{ upsert: true }
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteGame(game) {
|
||||
return collection.deleteOne({ game });
|
||||
}
|
||||
|
||||
export async function deleteField(game, key) {
|
||||
return collection.updateOne({ game }, { $unset: { [key]: '' } });
|
||||
}
|
||||
Reference in New Issue
Block a user