Skip to content

Commit

Permalink
Merge pull request #65 from Nick-NCSU/add-guild-commands
Browse files Browse the repository at this point in the history
Add guild commands
  • Loading branch information
Nick-NCSU authored Aug 7, 2022
2 parents 3b09567 + a5b496f commit ba3b509
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 83 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
token=""
id=""
guildid=""
hypixel=""
mongourl=""
srcapi=""
3 changes: 2 additions & 1 deletion commands/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
.setDescription("Game to show categories")
.setRequired(true)
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const game = interaction.options.get("game").value.toLowerCase();
// Fetches the categories
const { data } = await tokens.fetch(`https://www.speedrun.com/api/v1/games?abbreviation=${game}&embed=categories.variables`);
Expand Down
3 changes: 2 additions & 1 deletion commands/dream.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ module.exports = {
option.setName("simulations")
.setDescription("Number of simulations to run (Max 100,000")
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
let sim = interaction.options.get("simulations");
// If the number of simulations was not specified then set sim to 1
if(!sim) {
Expand Down
3 changes: 2 additions & 1 deletion commands/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module.exports = {
data: new SlashCommandBuilder()
.setName("help")
.setDescription("Provides a list of commands and descriptions."),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const embed = new EmbedBuilder()
.setColor("#118855")
.setTitle("Help")
Expand Down
3 changes: 2 additions & 1 deletion commands/leaderboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ module.exports = {
option.setName("ils")
.setDescription("Include Individual Levels? Default: true")
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
// From rsp via https://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in-javascript
// Provides cartesian product of arrays
const cartesian = (...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
Expand Down
3 changes: 2 additions & 1 deletion commands/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
.setDescription("Game to link")
.setRequired(true)
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const game = interaction.options.get("game").value.toLowerCase();
// Gets the requested game
const {data} = await tokens.fetch(`https://www.speedrun.com/api/v1/games?abbreviation=${game}`);
Expand Down
3 changes: 2 additions & 1 deletion commands/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module.exports = {
data: new SlashCommandBuilder()
.setName("ping")
.setDescription("Provides bot response time."),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const embed = new EmbedBuilder()
.setColor("#118855")
.setThumbnail("https://www.speedrun.com/images/1st.png")
Expand Down
3 changes: 2 additions & 1 deletion commands/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ module.exports = {
option.setName("page")
.setDescription("Which page would you like to view?")
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const search = interaction.options.get("query").value.toLowerCase();
let page = interaction.options.get("page");
// If page is not specified default to 1
Expand Down
3 changes: 2 additions & 1 deletion commands/unverified.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
.setDescription("Game to search")
.setRequired(true)
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const game = interaction.options.get("game").value.toLowerCase();
// Gets the game for the id
const gameData = await tokens.fetch(`https://www.speedrun.com/api/v1/games/${game}`);
Expand Down
3 changes: 2 additions & 1 deletion commands/verified.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
.setDescription("User to search")
.setRequired(true)
),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
const user = interaction.options.get("user").value.toLowerCase();
// Search for user on speedrun.com
const playerData = await tokens.fetch(`https://www.speedrun.com/api/v1/users/${user}`);
Expand Down
3 changes: 2 additions & 1 deletion commands/hypixel.js → guildcommands/hypixel.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module.exports = {
data: new SlashCommandBuilder()
.setName("hypixel")
.setDescription("Provides helpful links for Hypixel Speedruns"),
async execute(interaction) {
async execute(params) {
const { interaction } = params;
// Initial running of the command
if(interaction.type === InteractionType.ApplicationCommand) {
const row = new ActionRowBuilder()
Expand Down
49 changes: 49 additions & 0 deletions guildcommands/suggest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { EmbedBuilder } = require("discord.js");
const { SlashCommandBuilder } = require("@discordjs/builders");

/**
* Function to provide a list of categories for the given game
*/
module.exports = {
/**
* Builds /categories [string:game]
*/
data: new SlashCommandBuilder()
.setName("suggest")
.setDescription("Create a suggestion")
.addStringOption(option =>
option.setName("title")
.setDescription("Title of the suggestion (max 256 characters).")
.setRequired(true)
)
.addStringOption(option =>
option.setName("description")
.setDescription("Description fo the suggestion (max 4096 characters).")
.setRequired(true)
),
async execute(params) {
const { interaction, client } = params;
const channel = await client.channels.cache.get("1005944361709731981");
const title = interaction.options.get("title").value;
const description = interaction.options.get("description").value;

let date = new Date().toISOString().slice(0, 10);
let embed = new EmbedBuilder()
.setColor("#118855")
.setTitle(title.slice(0, 256))
.setFooter({ text: `${date}` })
.setDescription(description.slice(0, 4096))
.addFields([
{ name: "Submitted by:", value: `<@${interaction.user.id}>`}
]);
let message = await channel.send({ embeds: [embed] });
message.react("👍");
message.react("👎");
message.startThread({
name: title.slice(0, 64),
});
await interaction.editReply({
content: "Suggestion has been created: " + message.url
});
},
};
124 changes: 66 additions & 58 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
// Imports
const { Client, GatewayIntentBits, Collection, InteractionType } = require("discord.js");
const { Client, GatewayIntentBits, Collection, InteractionType, Routes, ActivityType } = require("discord.js");
const fs = require("fs");
const Limit = require("./Limiter.js");
const Queue = require("queue-promise");
const limiter = new Limit(95, 70000);
const mojangLimiter = new Limit(600, 600000);
const hypixelLimiter = new Limit(120, 60000);
// const { REST } = require("@discordjs/rest");
// const { Routes } = require("discord-api-types/v9");
const { REST } = require("@discordjs/rest");
const fetch = (...args) => import("node-fetch").then(({default: fetch}) => fetch(...args));
const { MongoClient } = require("mongodb");
var cron = require("node-cron");
require("dotenv").config();

// Creates a rate limiting queue
const queue = new Queue({
concurrent: 1
});

// Prefix to call the bot
const prefix = "src!";
// Determines the token for bot

let token = process.env.token;
let hypixel = process.env.hypixel;
let mongourl = process.env.mongourl;
let src = process.env.srcapi;

const limiter = new Limit(95, 70 * 1000);
const mojangLimiter = new Limit(600, 600 * 1000);
const hypixelLimiter = new Limit(120, 60 * 1000);

// Creates new Client
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
client.commands = new Collection();
client.msgCommands = new Collection();
client.guildCommands = new Collection();

const commands = [];
const commandFiles = fs.readdirSync("./commands").filter(file => file.endsWith(".js"));

for (const file of commandFiles) {
const command = require(`./commands/${file}`);
commands.push(command.data.toJSON());
getCommands("./commands", (command) => {
client.commands.set(command.data.name, command);
}

const msgCommandFiles = fs.readdirSync("./messagecommands").filter(file => file.endsWith(".js"));

for (const file of msgCommandFiles) {
const command = require(`./messagecommands/${file}`);
});
getCommands("./messagecommands", (command) => {
client.msgCommands.set(command.data.name, command);
}

// const rest = new REST({ version: '9' }).setToken(token);
// (async () => {
// try {
// console.log('Started refreshing application (/) commands.');

// await rest.put(
// Routes.applicationCommands(process.env.id),
// { body: commands },
// );

// console.log('Successfully reloaded application (/) commands.');
// } catch (error) {
// console.error(error);
// }
// })();


const scheduledCommandFiles = fs.readdirSync("./scheduledcommands").filter(file => file.endsWith(".js"));

for (const file of scheduledCommandFiles) {
const command = require(`./scheduledcommands/${file}`);
});
getCommands("./guildcommands", (command) => {
client.guildCommands.set(command.data.name, command);
});
getCommands("./scheduledcommands", (command) => {
cron.schedule(command.data.interval, () => {
command.execute(client);
});
});

function getCommands(dir, callback) {
const files = fs.readdirSync(dir).filter(file => file.endsWith(".js"));

for (const file of files) {
const command = require(`${dir}/${file}`);
callback(command);
}
}

const rest = new REST({ version: "10" }).setToken(token);

// Sets bot activity and announces that bot is ready for use
client.once("ready", async () => {
client.user.setActivity("speedrun.com | /help", { type: "WATCHING" });
client.user.setActivity("speedrun.com | /help", { type: ActivityType.Watching });
console.log("Ready!");

try {
console.log("Started refreshing application (/) commands.");

await rest.put(
Routes.applicationGuildCommands(process.env.id, process.env.guildid),
{ body: client.guildCommands.map(command => command.data.toJSON()) },
);

const commandValues = new Set((await client.application.commands.fetch()).map(command => command.name));
const commands = new Set(client.commands.map(command => command.data.name));
if(commandValues.size !== commands.size || ![...commandValues].every(command => commands.has(command))) {
await rest.put(
Routes.applicationCommands(process.env.id),
{ body: client.commands.map(command => command.data.toJSON()) },
);
console.log("Successfully reloaded application (/) commands.");
return;
}

console.log("No (/) commands to reload.");
} catch (error) {
console.error(error);
}
});

client.on("messageCreate", async message => {
Expand All @@ -94,16 +97,26 @@ client.on("messageCreate", async message => {

client.on("interactionCreate", async interaction => {
if(interaction.type === InteractionType.ApplicationCommand) {
if (!client.commands.has(interaction.commandName)) return;
if (!client.commands.has(interaction.commandName) && !client.guildCommands.has(interaction.commandName)) return;
await interaction.deferReply();
try {
await client.commands.get(interaction.commandName).execute(interaction);
if(client.commands.has(interaction.commandName)) {
await client.commands.get(interaction.commandName).execute({
interaction,
client
});
} else {
await client.guildCommands.get(interaction.commandName).execute({
interaction,
client
});
}
} catch (error) {
console.error(error);
await interaction.editReply({ content: "There was an error while executing this command!", ephemeral: true });
}
} else if(interaction.isSelectMenu()) {
await client.commands.get("hypixel").execute(interaction);
await client.guildCommands.get("hypixel").execute(interaction);
}
});

Expand All @@ -117,10 +130,6 @@ exports.limit = function getLimit() {
return limiter;
};

exports.queue = function getQueue() {
return queue;
};

exports.fetch = async function limitFetch(text) {
let data;
while(true) {
Expand Down Expand Up @@ -161,6 +170,5 @@ function sleep(ms) {
});
}

const uri = mongourl;
const dbclient = new MongoClient(uri);
const dbclient = new MongoClient(mongourl);
exports.db = dbclient;
14 changes: 0 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"node-cron": "^3.0.1",
"node-fetch": "^3.2.10",
"perf_hooks": "0.0.1",
"queue-promise": "^2.2.1",
"uuid": "^8.3.2"
},
"engines": {
Expand Down

0 comments on commit ba3b509

Please sign in to comment.