From ce3c8f07bd879c8e1d479ed5486767510969ea4a Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 08:52:26 +0100 Subject: [PATCH 01/28] fixed potential bug, idfk --- commands/economy/beg.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/economy/beg.js b/commands/economy/beg.js index ef7340e..12c2c4b 100644 --- a/commands/economy/beg.js +++ b/commands/economy/beg.js @@ -9,7 +9,7 @@ module.exports = { cooldown: 60, run(client, message, args, guildData, userData, isSlashCommand) { - if (userData.economy.wallet < 200) + if (userData.economy?.wallet < 200) return "Not enough money to risk on losing"; const earned = Math.round(Math.random() * 400) - 200; userData.economy.wallet += earned; From 0e4b202b4e9ba9301bdeb9ce471d80cdf8f88f77 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 08:53:27 +0100 Subject: [PATCH 02/28] made changes to cooldown system --- buttons/economy/search.js | 16 ++++ commands/economy/search.js | 160 ++++++++++++++++++++++++++++++------ commands/economy/work.js | 2 +- functions/convertTime.js | 28 +++++++ functions/executeCommand.js | 24 ++++-- 5 files changed, 197 insertions(+), 33 deletions(-) create mode 100644 buttons/economy/search.js create mode 100644 functions/convertTime.js diff --git a/buttons/economy/search.js b/buttons/economy/search.js new file mode 100644 index 0000000..91053d1 --- /dev/null +++ b/buttons/economy/search.js @@ -0,0 +1,16 @@ +const userList = require("../../schemas/user.js"); +const { Random } = require("sussy-util"); + +module.exports = { + name: "search", + cooldown: 60, + async run(client, interaction, args, guildData, userData) { + const amount = Random.randomInt(900, 1600); + const current = userData.economy; + current.wallet += amount; + userList.findByIdAndUpdate(userData._id, { economy: current }, (err, data) => { }); + userData.level.xp += 2; + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); + return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; + } +} \ No newline at end of file diff --git a/commands/economy/search.js b/commands/economy/search.js index 43b4f67..d48e5c1 100644 --- a/commands/economy/search.js +++ b/commands/economy/search.js @@ -1,5 +1,5 @@ -const { Random } = require("sussy-util"); -const { EmbedBuilder, Colors } = require("discord.js"); +const { StringUtil } = require("sussy-util"); +const { EmbedBuilder, Colors, ActionRowBuilder, StringSelectMenuBuilder, SelectMenuOptionBuilder, ButtonStyle, ButtonBuilder } = require("discord.js"); const userList = require("../../schemas/user"); module.exports = { @@ -7,28 +7,142 @@ module.exports = { cooldown: 60, run: (_client, message, _args, _guildData, userData) => { - const places = ["bank", "river", "pocket"]; - const collector = message.channel.createMessageCollector({ filter: msg => msg.author.id === message.author.id, time: 30000 }); - - collector.on("collect", async msg => { - if (places.includes(msg.content)) { - const amount = Random.randomInt(900, 1600); - const current = userData.economy; - current.wallet += amount; - userList.findByIdAndUpdate(userData._id, { economy: current }, (err, data) => { }); - userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); - message.followUp(`You found ${amount} gold in the ${msg.content}.`); - collector.stop("success"); - } - }); + const places = [ + "bank", + "river", + "pocket", + "car", + "house", + "garden", + "street", + "park", + "school", + "work", + "shop", + "gym", + "hospital", + "church", + "library", + "mall", + "beach", + "forest", + "mountain", + "cave", + "farm", + "factory", + "office", + "hotel", + "museum", + "zoo", + "casino", + "bar", + "restaurant", + "club", + "parking lot", + "bus stop", + "train station", + "airport", + "police station", + "fire station", + "post office", + "bank", + "supermarket", + "bakery", + "butcher", + "pharmacy", + "hardware store", + "bookstore", + "clothing store", + "jewelry store", + "pet store", + "toy store", + "furniture store", + "car dealership", + "car repair shop", + "car wash", + "gas station", + "laundry", + "dry cleaner", + "hair salon", + "spa", + "tattoo parlor", + "barber shop", + "dentist", + "doctor", + "optician", + "veterinarian", + "golf course", + "bowling alley", + "amusement park", + "movie theater", + "concert hall", + "stadium", + "aquarium", + "circus", + "casino", + "bar", + "restaurant", + "club", + "parking lot", + "bus stop", + "train station", + "airport", + "police station", + "fire station", + "post office", + "bank", + "supermarket", + "bakery", + "butcher", + "pharmacy", + "hardware store", + "bookstore", + "clothing store", + "jewelry store", + "pet store", + "toy store", + "furniture store", + "car dealership", + "car repair shop", + "car wash", + "gas station", + "laundry", + "dry cleaner", + "hair salon", + "spa", + "tattoo parlor", + "barber shop", + "dentist", + "doctor", + "optician", + "veterinarian", + "golf course", + "bowling alley", + "amusement park", + "movie theater", + "concert hall", + "stadium", + "aquarium", + "circus"]; + + const actionRow = new ActionRowBuilder() + + const embed = new EmbedBuilder(true) + .setTitle("Search") + .setColor(Colors.Red) + .setDescription("Where do you want to search?"); - collector.on("end", async (_ignore, error) => { - if (error && error !== 'success') { - return message.followUp({ embeds: [new EmbedBuilder().setTitle("Timed Out").setColor(Colors.Red)] }); - } - collector.stop("success"); + const randomElements = places.sort(() => Math.random() - 0.5).slice(0, 5); + + randomElements.forEach(place => { + const button = new ButtonBuilder() + .setLabel(StringUtil.capitalize(place)) + .setCustomId(`search ${place}`) + .setStyle(ButtonStyle.Primary); + + actionRow.addComponents(button); }); - return "Please tell me where you want to search.\n" + places.map(e => "`" + e + "`").join(", "); + + return { embeds: [embed], components: [actionRow] }; } } \ No newline at end of file diff --git a/commands/economy/work.js b/commands/economy/work.js index 25f2016..cfa9d60 100644 --- a/commands/economy/work.js +++ b/commands/economy/work.js @@ -16,7 +16,7 @@ module.exports = { if (!(Math.floor(userData.level.xp / 50) === (Math.floor((userData.level.xp - 5) / 50)))) { message.channel.send(`<@${userData.userId}>` + " just levelled up!") } - return ("Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!"); + return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", success: [this] }; } } } diff --git a/functions/convertTime.js b/functions/convertTime.js new file mode 100644 index 0000000..094ad13 --- /dev/null +++ b/functions/convertTime.js @@ -0,0 +1,28 @@ +module.exports = (seconds) => { + const timeObj = secondsConverter(seconds, "sec"); + let returnString = ""; + if (timeObj.days > 0) + returnString += `${timeObj.days}d`; + if (timeObj.hours > 0) + returnString += `${timeObj.hours}h`; + if (timeObj.minutes > 0) + returnString += `${timeObj.minutes}m`; + if (timeObj.seconds > 0) + returnString += `${timeObj.seconds}s`; + if (returnString !== "") + return returnString; + else + return "0s"; +} + +function secondsConverter(seconds) { + const timeObj = {}; + timeObj.days = Math.floor(seconds / 86400); + seconds -= timeObj.days * 86400; + timeObj.hours = Math.floor(seconds / 3600); + seconds -= timeObj.hours * 3600; + timeObj.minutes = Math.floor(seconds / 60); + seconds -= timeObj.minutes * 60; + timeObj.seconds = seconds; + return timeObj; +} \ No newline at end of file diff --git a/functions/executeCommand.js b/functions/executeCommand.js index 45e1a18..8487e0d 100644 --- a/functions/executeCommand.js +++ b/functions/executeCommand.js @@ -30,7 +30,7 @@ module.exports = async (command, client, interaction, args, isInteraction, isCom } if (client.commandCooldowns.get(command.name).get(interaction.author.id) !== undefined) - return interaction.reply("You are on cooldown for this command! Wait another " + Math.round((client.commandCooldowns.get(command.name).get(interaction.author.id) - Date.now()) / 1000) + " seconds."); + return interaction.reply("You are on cooldown for this command! Wait another " + client.functions.convertTime(Math.round((client.commandCooldowns.get(command.name).get(interaction.author.id) - Date.now()) / 1000)) + "."); // makes reply unavailable so two replies can't be sent const reply = interaction.reply; @@ -55,15 +55,21 @@ module.exports = async (command, client, interaction, args, isInteraction, isCom return; } - let cooldown; - if (returnValue.cooldown) cooldown = returnValue.cooldown; - else cooldown = command.cooldown; + let success = returnValue.success || command.success; - if (cooldown && returnValue.success !== false) { - client.commandCooldowns.get(command.name).set(interaction.author.id, Date.now() + cooldown * 1000); - setTimeout(() => { - client.commandCooldowns.get(command.name).delete(interaction.author.id); - }, cooldown * 1000); + if (success !== undefined && success !== null) { + let cooldownArray = returnValue.success || command.success || [command.cooldown !== undefined]; + + cooldownArray.forEach(commandObject => { + if (typeof commandObject === "string") + commandObject = client.commands.get(commandObject); + if (commandObject === undefined) return console.error("Could not set cooldown, command not found: " + commandObject); + if (typeof commandObject.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + commandObject.name); + client.commandCooldowns.get(commandObject.name).set(interaction.author.id, Date.now() + commandObject.cooldown * 1000); + setTimeout(() => { + client.commandCooldowns.get(commandObject.name).delete(interaction.author.id); + }, commandObject.cooldown * 1000); + }); } // makes reply available again From 63609ba23ec3c1e5fe0832b2ec30de7886684684 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 08:53:37 +0100 Subject: [PATCH 03/28] fixed deprecation warning --- events/discord/interactionCreate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/events/discord/interactionCreate.js b/events/discord/interactionCreate.js index 0fef54e..883fba8 100644 --- a/events/discord/interactionCreate.js +++ b/events/discord/interactionCreate.js @@ -12,7 +12,7 @@ module.exports = async (client, interaction) => { if (interaction.isCommand()) type = "COMMAND"; else if (interaction.isButton()) type = "BUTTON"; - else if (interaction.isSelectMenu()) type = "SELECT_MENU"; + else if (interaction.isStringSelectMenu()) type = "SELECT_MENU"; else throw new Error("Unknown interaction type"); switch (type) { From 52624ed332b57c76c09f1475cfb515b2b4556f8e Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 09:26:43 +0100 Subject: [PATCH 04/28] fixed clear command --- Commands.md | 2 +- Issues.md | 4 +-- commands/moderation/clear.js | 57 ++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/Commands.md b/Commands.md index ecc980c..92072a0 100644 --- a/Commands.md +++ b/Commands.md @@ -30,7 +30,7 @@ ## Moderation -- [ ] clear +- [x] clear - [ ] lock - [ ] nickname - [ ] prepare diff --git a/Issues.md b/Issues.md index 5d86036..120d222 100644 --- a/Issues.md +++ b/Issues.md @@ -1,6 +1,6 @@ # Issues -- [ ] When outputting time, format seconds to seconds, minutes, hours, days, ... +- [x] When outputting time, format seconds to seconds, minutes, hours, days, ... - [x] When resetting balance/level the YES/NO message can be seen by everyone which would reset the balance of everyone clicking on the button - [ ] Fix help command - [x] Fix coinflip: returned nothing @@ -53,6 +53,6 @@ message_reference: Unknown message } } - [x] troll returns nothing -- [ ] search gives you a cooldown even when you didn't search anything +- [x] search gives you a cooldown even when you didn't search anything - [ ] job doesn't display which level is required to get the job - [ ] coinflip "You are victorious!"... Like WTF?! Mb think 5 secs before writing that diff --git a/commands/moderation/clear.js b/commands/moderation/clear.js index ee54bd4..aeab626 100644 --- a/commands/moderation/clear.js +++ b/commands/moderation/clear.js @@ -2,7 +2,6 @@ const { ManageMessages } = require("../../enums/permissionBitField"); const { ManageMessages: manageMsgs } = require("../../enums/permissionStrings"); module.exports = { - ignore: true, description: "Clears the last n messages", options: [ @@ -19,23 +18,63 @@ module.exports = { async run(client, message, args, guildData, userData, isSlashCommand) { const amount = parseInt(args[0]); - if (isNaN(amount)) return "Please provide a number as the first argument."; + if (args[0] === "all") { + clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { + if (isSlashCommand) + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch(err => { + if (isSlashCommand) + message.followUp(err); + else + message.channel.send + }); + + return null; + } else if (isNaN(amount)) return "Please provide a number as the first argument."; if (amount <= 0) return "Number must be at least 1."; + clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { + if (isSlashCommand) + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch(err => { + if (isSlashCommand) + message.followUp(err); + else + message.channel.send(err); + }); + + return null; + } +} + +function clearMessages(message, amount, isSlashCommand = false) { + return new Promise(async (resolve, reject) => { let deletedMessagesCount = isSlashCommand ? 0 : -1; while (deletedMessagesCount < amount) { const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); const deletedMessages = await message.channel.bulkDelete(deleteThisTime, true) - .catch(err => message.channel.send("An error occurred.")); + .catch(err => reject("Cannot delete messages older than two weeks.")); if (deletedMessages === undefined || deletedMessages.size === 0) break; deletedMessagesCount += deletedMessages.size; } + resolve(deletedMessagesCount); + }); +} - if (deletedMessagesCount === 0) { - return "I can't delete messages which are older than two weeks."; +function clearAllMessages(message, isSlashCommand = false) { + return new Promise(async (resolve, reject) => { + let deletedMessagesCount = isSlashCommand ? 0 : -1; + while (true) { + const deletedMessages = await message.channel.bulkDelete(100, true) + .catch(err => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === undefined || deletedMessages.size === 0) break; + deletedMessagesCount += deletedMessages.size; } - - message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>`).then(msg => setTimeout(() => msg.delete(), 5000)); - } -} + resolve(deletedMessagesCount); + }); +} \ No newline at end of file From 1f525e40a2a58fb1ad6961348cbeec2b397df272 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 10:24:41 +0100 Subject: [PATCH 05/28] removed todo --- functions/executeCommand.js | 1 - 1 file changed, 1 deletion(-) diff --git a/functions/executeCommand.js b/functions/executeCommand.js index 8487e0d..06e5561 100644 --- a/functions/executeCommand.js +++ b/functions/executeCommand.js @@ -1,5 +1,4 @@ // TODO: Add automated argument checking -// TODO: Add automated permission checking const getGuildData = require("./getGuildData.js"); const getUserData = require("./getUserData.js"); From 98a7007a6f0e9d47cc37150d51f1f1ff4f476a8d Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 13:16:32 +0100 Subject: [PATCH 06/28] made functions global slight performance improvement in execute command --- commands/moderation/lock.js | 3 +-- commands/moderation/set-counter-channel.js | 3 +-- commands/moderation/set-goodbye-channel.js | 3 +-- commands/moderation/set-welcome-channel.js | 3 +-- commands/moderation/slowmode.js | 2 +- commands/moderation/unlock.js | 3 +-- events/discord/guildCreate.js | 3 +-- events/discord/guildMemberAdd.js | 3 +-- events/discord/guildMemberRemove.js | 3 +-- events/discord/interactionCreate.js | 4 +--- events/discord/messageCreate.js | 12 ++++-------- functions/executeCommand.js | 11 ++++++++--- index.js | 12 +----------- 13 files changed, 23 insertions(+), 42 deletions(-) diff --git a/commands/moderation/lock.js b/commands/moderation/lock.js index 5f97862..4cb332f 100644 --- a/commands/moderation/lock.js +++ b/commands/moderation/lock.js @@ -1,6 +1,5 @@ const { ManageChannels, SendMessages } = require("../../enums/permissionBitField"); const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const getChannelFromMention = require("../../functions/getChannelFromMention"); const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -19,7 +18,7 @@ module.exports = { default_member_permissions: ManageChannel, run(client, message, args, guildData, userData, isSlashCommand) { - let channel = getChannelFromMention(message.guild, args[0]); + let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; if (!channel.permissionsFor(message.guild.roles.everyone).has(SendMessages)) diff --git a/commands/moderation/set-counter-channel.js b/commands/moderation/set-counter-channel.js index 71c443d..b50ecfd 100644 --- a/commands/moderation/set-counter-channel.js +++ b/commands/moderation/set-counter-channel.js @@ -1,6 +1,5 @@ const { ManageChannels } = require("../../enums/permissionBitField"); const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const getChannelFromMention = require("../../functions/getChannelFromMention"); const guilds = require("../../schemas/guild"); module.exports = { @@ -20,7 +19,7 @@ module.exports = { default_member_permissions: ManageChannel, async run(client, message, args, guildData, userData, isSlashCommand) { - let channel = getChannelFromMention(message.guild, args[0]); + let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; const current = guildData.channels; current.counter = channel.id; diff --git a/commands/moderation/set-goodbye-channel.js b/commands/moderation/set-goodbye-channel.js index ca2516f..e28c805 100644 --- a/commands/moderation/set-goodbye-channel.js +++ b/commands/moderation/set-goodbye-channel.js @@ -1,6 +1,5 @@ const { ManageChannels } = require("../../enums/permissionBitField"); const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const getChannelFromMention = require("../../functions/getChannelFromMention"); const guilds = require("../../schemas/guild"); module.exports = { @@ -20,7 +19,7 @@ module.exports = { default_member_permissions: ManageChannel, async run(client, message, args, guildData, userData, isSlashCommand) { - const channel = getChannelFromMention(message.guild, args[0]); + const channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; const current = guildData.channels; current.goodbye = channel.id; diff --git a/commands/moderation/set-welcome-channel.js b/commands/moderation/set-welcome-channel.js index 56b4616..d3a5238 100644 --- a/commands/moderation/set-welcome-channel.js +++ b/commands/moderation/set-welcome-channel.js @@ -1,6 +1,5 @@ const { ManageChannels } = require("../../enums/permissionBitField"); const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const getChannelFromMention = require("../../functions/getChannelFromMention"); const guilds = require("../../schemas/guild"); module.exports = { @@ -20,7 +19,7 @@ module.exports = { default_member_permissions: ManageChannel, async run(client, message, args, guildData, userData, isSlashCommand) { - const channel = getChannelFromMention(message.guild, args[0]); + const channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; const current = guildData.channels; current.welcome = channel.id; diff --git a/commands/moderation/slowmode.js b/commands/moderation/slowmode.js index 61c9e62..3bb5ad8 100644 --- a/commands/moderation/slowmode.js +++ b/commands/moderation/slowmode.js @@ -25,7 +25,7 @@ module.exports = { run(client, message, args, guildData, userData, isSlashCommand) { let rate; - let channel = client.functions.getChannelFromMention(message.guild, args[0]); + let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) { channel = message.channel; rate = args[0]; diff --git a/commands/moderation/unlock.js b/commands/moderation/unlock.js index 3c70397..944277f 100644 --- a/commands/moderation/unlock.js +++ b/commands/moderation/unlock.js @@ -1,6 +1,5 @@ const { ManageChannels, SendMessages } = require("../../enums/permissionBitField"); const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const getChannelFromMention = require("../../functions/getChannelFromMention"); const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -19,7 +18,7 @@ module.exports = { default_member_permissions: ManageChannel, run(client, message, args, guildData, userData, isSlashCommand) { - let channel = getChannelFromMention(message.guild, args[0]); + let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; if (channel.permissionsFor(message.guild.roles.everyone).has(SendMessages)) diff --git a/events/discord/guildCreate.js b/events/discord/guildCreate.js index b32bed5..4c1841a 100644 --- a/events/discord/guildCreate.js +++ b/events/discord/guildCreate.js @@ -1,4 +1,3 @@ -const addGuildDocument = require("../../functions/addGuildDocument"); const guildModel = require("../../schemas/guild"); module.exports = async (client, guild) => { @@ -7,7 +6,7 @@ module.exports = async (client, guild) => { console.info("Creating MongoDB entry for guild " + guild.name); - addGuildDocument(guild.id); + global.functions.addGuildDocument(guild.id); client.commands.forEach(command => { if (command.name === "prepare") return; diff --git a/events/discord/guildMemberAdd.js b/events/discord/guildMemberAdd.js index e9b3d12..e911631 100644 --- a/events/discord/guildMemberAdd.js +++ b/events/discord/guildMemberAdd.js @@ -1,11 +1,10 @@ const fetchData = require("../../config.js").fetchData; const welcomeMessages = fetchData.get("messages").welcome; const guilds = require("../../schemas/guild"); -const replaceUser = require("../../functions/replaceUser.js"); module.exports = async (client, member) => { const guild = await guilds.findOne({ guildId: member.guild.id }); if (guild?.channels?.welcome === undefined) return; const channel = client.channels.cache.get(guild.channels.welcome); - channel.send(replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); + channel.send(global.functions.replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); } diff --git a/events/discord/guildMemberRemove.js b/events/discord/guildMemberRemove.js index e0f19c0..c2ea2b6 100644 --- a/events/discord/guildMemberRemove.js +++ b/events/discord/guildMemberRemove.js @@ -1,11 +1,10 @@ const fetchData = require("../../config.js").fetchData; const goodbyeMessages = fetchData.get("messages").goodbye; const guilds = require("../../schemas/guild"); -const replaceUser = require("../../functions/replaceUser.js"); module.exports = async (client, member) => { const guild = await guilds.findOne({ guildId: member.guild.id }); if (!guild?.channels?.goodbye) return; const channel = client.channels.cache.get(guild?.channels?.goodbye); - channel.send(replaceUser(goodbyeMessages[Math.floor(Math.random() * goodbyeMessages.length)], member)); + channel.send(global.functions.replaceUser(goodbyeMessages[Math.floor(Math.random() * goodbyeMessages.length)], member)); } diff --git a/events/discord/interactionCreate.js b/events/discord/interactionCreate.js index 883fba8..02d4173 100644 --- a/events/discord/interactionCreate.js +++ b/events/discord/interactionCreate.js @@ -1,5 +1,3 @@ -const executeCommand = require("../../functions/executeCommand.js"); - module.exports = async (client, interaction) => { let cmd; let args = []; @@ -44,5 +42,5 @@ module.exports = async (client, interaction) => { interaction.channel = client.channels.cache.get(interaction.channelId); interaction.author = interaction.user; - executeCommand(cmd, client, interaction, args, true, isComponent); + global.functions.executeCommand(cmd, client, interaction, args, true, isComponent); } diff --git a/events/discord/messageCreate.js b/events/discord/messageCreate.js index b0f0824..2f73ff3 100644 --- a/events/discord/messageCreate.js +++ b/events/discord/messageCreate.js @@ -1,16 +1,12 @@ -const addGuildDocument = require("../../functions/addGuildDocument"); -const executeCommand = require("../../functions/executeCommand.js"); const guildModel = require("../../schemas/guild"); module.exports = async (client, message) => { if (message.author.bot) return; // Ignore bots const guildData = await getGuildData(message.guild.id); - const counter = require("../../functions/counter.js"); - if (counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function + if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function - const isBotChannel = require("../../functions/checkChannelID.js"); - if (!isBotChannel(message, guildData)) return; // Ignore messages not in allowed channels + if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels const prefix = client.config.prefix; // Get the prefix from the .env file @@ -22,13 +18,13 @@ module.exports = async (client, message) => { client.commands.find(command => command.aliases && command.aliases.includes(commandString)); message.followUp = message.reply; - executeCommand(command, client, message, args, false); // Execute the command + global.functions.executeCommand(command, client, message, args, false); // Execute the command } async function getGuildData(guildId) { let guildData = await guildModel.findOne({ guildId: guildId }); if (!guildData) { - addGuildDocument(guildId); + global.functions.addGuildDocument(guildId); guildData = await guildModel.findOne({ guildId: guildId }); } return guildData; diff --git a/functions/executeCommand.js b/functions/executeCommand.js index 06e5561..4e210ba 100644 --- a/functions/executeCommand.js +++ b/functions/executeCommand.js @@ -24,12 +24,17 @@ module.exports = async (command, client, interaction, args, isInteraction, isCom return interaction.reply("You need to be in a voice channel to use this command."); if (command.connectedToSameVoiceChannel && client.player.getQueue(interaction.guildId)?.voiceChannel !== interaction.member.voice?.channel.id) { - if (client.player.getQueue(interaction.guildId)?.voiceChannel === undefined) return interaction.reply("I am not in a voice channel."); + if (client.player.getQueue(interaction.guildId)?.voiceChannel === undefined) + return interaction.reply("I am not in a voice channel."); return interaction.reply("You need to be in the same voice channel as me to use this command."); } - if (client.commandCooldowns.get(command.name).get(interaction.author.id) !== undefined) - return interaction.reply("You are on cooldown for this command! Wait another " + client.functions.convertTime(Math.round((client.commandCooldowns.get(command.name).get(interaction.author.id) - Date.now()) / 1000)) + "."); + const cooldown = client.commandCooldowns.get(command.name).get(interaction.author.id); + if (cooldown !== undefined) + return interaction.reply("You are on cooldown for this command! Wait another " + + global.functions.convertTime( + Math.round(cooldown - Date.now()) / 1000) + + "."); // makes reply unavailable so two replies can't be sent const reply = interaction.reply; diff --git a/index.js b/index.js index ace5e14..635ea5c 100644 --- a/index.js +++ b/index.js @@ -13,16 +13,6 @@ require("better-cl").setup(console, [], "./logs"); console.clear(); -/* Create a new client instance */ -// const client = new Client({ -// intents: [ -// Intents.FLAGS.GUILDS, -// Intents.FLAGS.GUILD_MEMBERS, -// Intents.FLAGS.GUILD_MESSAGES, -// Intents.FLAGS.GUILD_VOICE_STATES -// ] -// }); - const client = new Client({ intents: [ GatewayIntentBits.Guilds, @@ -42,7 +32,7 @@ client.connection = connection; console.log(`Version: ${client.config.version} by ${client.config.authorsString}`); /* Loading all the functions. */ -client.functions = require("./functions/getFiles")("./functions", "functions.js"); +global.functions = require("./functions/getFiles")("./functions", "functions.js"); /* Loading all the commands. */ loadCommands("commands"); From d7d34999160497128c80be1eb7d837fd2d636ce9 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Tue, 10 Jan 2023 23:43:39 +0100 Subject: [PATCH 07/28] started migration to ts --- package.json | 4 +-- tsconfig.json | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 tsconfig.json diff --git a/package.json b/package.json index dd14906..b6444fa 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node index.js" + "start": "(tsc || true) && node index.js" }, "repository": { "type": "git", @@ -37,4 +37,4 @@ "play-dl": "^1.9.6", "sussy-util": "^1.9.0-dev.0.0.4" } -} +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0d8bfbb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,95 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "ESnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} \ No newline at end of file From 8e925f016e7fbbc7f260db19a4772a88445924ed Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:39:57 +0100 Subject: [PATCH 08/28] converted everything to typescript, idk if it works, wish me luck! made roteKlaue happy with "void 0" --- .../{resetBalance.js => resetBalance.ts} | 6 +- .../economy/{resetLevel.js => resetLevel.ts} | 6 +- buttons/economy/{search.js => search.ts} | 12 +- buttons/general/{support.js => support.ts} | 6 +- .../music/{play_pause.js => play_pause.ts} | 8 +- commands/economy/{balance.js => balance.ts} | 5 +- commands/economy/{beg.js => beg.ts} | 17 +- commands/economy/{bet.js => bet.ts} | 13 +- commands/economy/{deposit.js => deposit.ts} | 12 +- commands/economy/{job.js => job.ts} | 23 +- commands/economy/{level.js => level.ts} | 6 +- .../{resetBalance.js => resetBalance.ts} | 10 +- .../economy/{resetLevel.js => resetLevel.ts} | 10 +- commands/economy/{search.js => search.ts} | 9 +- commands/economy/{withdraw.js => withdraw.ts} | 20 +- commands/economy/{work.js => work.ts} | 29 ++- commands/games/{coinflip.js => coinflip.ts} | 17 +- .../games/{numberguess.js => numberguess.ts} | 21 +- commands/general/{help.js => help.ts} | 21 +- commands/general/{info.js => info.ts} | 10 +- commands/general/invite.js | 8 - commands/general/invite.ts | 15 ++ .../general/{inviteBot.js => inviteBot.ts} | 5 +- .../general/{serverinfo.js => serverinfo.ts} | 15 +- commands/general/{userinfo.js => userinfo.ts} | 12 +- commands/moderation/clear.js | 80 ------- commands/moderation/clear.ts | 89 ++++++++ commands/moderation/{lock.js => lock.ts} | 21 +- .../moderation/{nickname.js => nickname.ts} | 21 +- .../moderation/{prepare.js => prepare.ts} | 16 +- ...{remove-nickname.js => remove-nickname.ts} | 19 +- ...nter-channel.js => set-counter-channel.ts} | 22 +- ...dbye-channel.js => set-goodbye-channel.ts} | 22 +- commands/moderation/set-welcome-channel.js | 30 --- commands/moderation/set-welcome-channel.ts | 36 +++ .../moderation/{slowmode.js => slowmode.ts} | 17 +- .../moderation/{tempban.js => tempban.ts} | 14 +- commands/moderation/{unban.js => unban.ts} | 22 +- commands/moderation/{unlock.js => unlock.ts} | 21 +- .../music/{clearQueue.js => clearQueue.ts} | 9 +- commands/music/{loop.js => loop.ts} | 10 +- commands/music/nowPlaying.js | 19 -- commands/music/nowPlaying.ts | 24 ++ commands/music/{pause.js => pause.ts} | 9 +- commands/music/{play.js => play.ts} | 10 +- commands/music/{queue.js => queue.ts} | 13 +- commands/music/{resume.js => resume.ts} | 9 +- commands/music/{shuffle.js => shuffle.ts} | 9 +- commands/music/{skip.js => skip.ts} | 9 +- commands/music/{stop.js => stop.ts} | 9 +- commands/music/{troll.js => troll.ts} | 10 +- commands/testcommands/{ping.js => ping.ts} | 17 +- .../testcommands/{playtest.js => playtest.ts} | 4 +- .../testcommands/{testbot.js => testbot.ts} | 7 +- .../testcommands/{uptime.js => uptime.ts} | 4 +- config.js => config.ts | 6 +- ...ssionBitField.js => permissionBitField.ts} | 4 +- ...missionStrings.js => permissionStrings.ts} | 2 +- events/discord/guildCreate.js | 15 -- events/discord/guildCreate.ts | 20 ++ events/discord/guildDelete.js | 6 - events/discord/guildDelete.ts | 9 + .../{guildMemberAdd.js => guildMemberAdd.ts} | 10 +- ...ldMemberRemove.js => guildMemberRemove.ts} | 8 +- ...eractionCreate.js => interactionCreate.ts} | 20 +- .../{messageCreate.js => messageCreate.ts} | 18 +- events/discord/ready.js | 4 - events/discord/ready.ts | 7 + events/mongodb/connected.js | 3 - events/mongodb/connected.ts | 6 + events/mongodb/connecting.js | 3 - events/mongodb/connecting.ts | 5 + events/mongodb/disconnected.js | 3 - events/mongodb/disconnected.ts | 5 + events/mongodb/err.js | 3 - events/mongodb/err.ts | 5 + ...ddGuildDocument.js => addGuildDocument.ts} | 8 +- ...{addUserDocument.js => addUserDocument.ts} | 4 +- .../{checkChannelID.js => checkChannelID.ts} | 6 +- functions/{convertTime.js => convertTime.ts} | 10 +- functions/counter.js | 11 - functions/counter.ts | 17 ++ functions/executeCommand.js | 149 ------------- functions/executeCommand.ts | 206 ++++++++++++++++++ ...chDataFromSave.js => fetchDataFromSave.ts} | 6 +- ...ommandReturn.js => formatCommandReturn.ts} | 18 +- ...romMention.js => getChannelFromMention.ts} | 4 +- functions/{getFiles.js => getFiles.ts} | 9 +- .../{getGuildData.js => getGuildData.ts} | 6 +- functions/{getUserData.js => getUserData.ts} | 6 +- functions/isValidYoutubeURL.js | 40 ---- functions/{replaceUser.js => replaceUser.ts} | 4 +- functions/sendMessage.js | 43 ---- functions/sendMessage.ts | 61 ++++++ functions/{shuffle.js => shuffle.ts} | 2 +- index.js => index.ts | 37 ++-- music/{player.js => player.ts} | 204 +++++++++-------- schemas/{guild.js => guild.ts} | 2 +- schemas/{user.js => user.ts} | 3 +- selectMenus/general/help.js | 5 - selectMenus/general/help.ts | 8 + types/client.ts | 24 ++ types/command.ts | 64 ++++++ www/{index.js => index.ts} | 4 +- www/routes/{commands.js => commands.ts} | 22 +- www/routes/{logo.js => logo.ts} | 2 +- www/static/commands/{index.js => index.ts} | 10 +- 107 files changed, 1277 insertions(+), 798 deletions(-) rename buttons/economy/{resetBalance.js => resetBalance.ts} (75%) rename buttons/economy/{resetLevel.js => resetLevel.ts} (73%) rename buttons/economy/{search.js => search.ts} (75%) rename buttons/general/{support.js => support.ts} (91%) rename buttons/music/{play_pause.js => play_pause.ts} (71%) rename commands/economy/{balance.js => balance.ts} (71%) rename commands/economy/{beg.js => beg.ts} (73%) rename commands/economy/{bet.js => bet.ts} (84%) rename commands/economy/{deposit.js => deposit.ts} (78%) rename commands/economy/{job.js => job.ts} (82%) rename commands/economy/{level.js => level.ts} (84%) rename commands/economy/{resetBalance.js => resetBalance.ts} (83%) rename commands/economy/{resetLevel.js => resetLevel.ts} (82%) rename commands/economy/{search.js => search.ts} (95%) rename commands/economy/{withdraw.js => withdraw.ts} (66%) rename commands/economy/{work.js => work.ts} (51%) rename commands/games/{coinflip.js => coinflip.ts} (62%) rename commands/games/{numberguess.js => numberguess.ts} (63%) rename commands/general/{help.js => help.ts} (78%) rename commands/general/{info.js => info.ts} (84%) delete mode 100644 commands/general/invite.js create mode 100644 commands/general/invite.ts rename commands/general/{inviteBot.js => inviteBot.ts} (71%) rename commands/general/{serverinfo.js => serverinfo.ts} (60%) rename commands/general/{userinfo.js => userinfo.ts} (71%) delete mode 100644 commands/moderation/clear.js create mode 100644 commands/moderation/clear.ts rename commands/moderation/{lock.js => lock.ts} (54%) rename commands/moderation/{nickname.js => nickname.ts} (65%) rename commands/moderation/{prepare.js => prepare.ts} (55%) rename commands/moderation/{remove-nickname.js => remove-nickname.ts} (65%) rename commands/moderation/{set-counter-channel.js => set-counter-channel.ts} (54%) rename commands/moderation/{set-goodbye-channel.js => set-goodbye-channel.ts} (52%) delete mode 100644 commands/moderation/set-welcome-channel.js create mode 100644 commands/moderation/set-welcome-channel.ts rename commands/moderation/{slowmode.js => slowmode.ts} (70%) rename commands/moderation/{tempban.js => tempban.ts} (58%) rename commands/moderation/{unban.js => unban.ts} (61%) rename commands/moderation/{unlock.js => unlock.ts} (54%) rename commands/music/{clearQueue.js => clearQueue.ts} (50%) rename commands/music/{loop.js => loop.ts} (54%) delete mode 100644 commands/music/nowPlaying.js create mode 100644 commands/music/nowPlaying.ts rename commands/music/{pause.js => pause.ts} (52%) rename commands/music/{play.js => play.ts} (62%) rename commands/music/{queue.js => queue.ts} (70%) rename commands/music/{resume.js => resume.ts} (52%) rename commands/music/{shuffle.js => shuffle.ts} (53%) rename commands/music/{skip.js => skip.ts} (60%) rename commands/music/{stop.js => stop.ts} (56%) rename commands/music/{troll.js => troll.ts} (60%) rename commands/testcommands/{ping.js => ping.ts} (62%) rename commands/testcommands/{playtest.js => playtest.ts} (98%) rename commands/testcommands/{testbot.js => testbot.ts} (68%) rename commands/testcommands/{uptime.js => uptime.ts} (93%) rename config.js => config.ts (66%) rename enums/{permissionBitField.js => permissionBitField.ts} (98%) rename enums/{permissionStrings.js => permissionStrings.ts} (98%) delete mode 100644 events/discord/guildCreate.js create mode 100644 events/discord/guildCreate.ts delete mode 100644 events/discord/guildDelete.js create mode 100644 events/discord/guildDelete.ts rename events/discord/{guildMemberAdd.js => guildMemberAdd.ts} (55%) rename events/discord/{guildMemberRemove.js => guildMemberRemove.ts} (60%) rename events/discord/{interactionCreate.js => interactionCreate.ts} (60%) rename events/discord/{messageCreate.js => messageCreate.ts} (68%) delete mode 100644 events/discord/ready.js create mode 100644 events/discord/ready.ts delete mode 100644 events/mongodb/connected.js create mode 100644 events/mongodb/connected.ts delete mode 100644 events/mongodb/connecting.js create mode 100644 events/mongodb/connecting.ts delete mode 100644 events/mongodb/disconnected.js create mode 100644 events/mongodb/disconnected.ts delete mode 100644 events/mongodb/err.js create mode 100644 events/mongodb/err.ts rename functions/{addGuildDocument.js => addGuildDocument.ts} (67%) rename functions/{addUserDocument.js => addUserDocument.ts} (63%) rename functions/{checkChannelID.js => checkChannelID.ts} (68%) rename functions/{convertTime.js => convertTime.ts} (77%) delete mode 100644 functions/counter.js create mode 100644 functions/counter.ts delete mode 100644 functions/executeCommand.js create mode 100644 functions/executeCommand.ts rename functions/{fetchDataFromSave.js => fetchDataFromSave.ts} (81%) rename functions/{formatCommandReturn.js => formatCommandReturn.ts} (63%) rename functions/{getChannelFromMention.js => getChannelFromMention.ts} (54%) rename functions/{getFiles.js => getFiles.ts} (60%) rename functions/{getGuildData.js => getGuildData.ts} (61%) rename functions/{getUserData.js => getUserData.ts} (60%) delete mode 100644 functions/isValidYoutubeURL.js rename functions/{replaceUser.js => replaceUser.ts} (51%) delete mode 100644 functions/sendMessage.js create mode 100644 functions/sendMessage.ts rename functions/{shuffle.js => shuffle.ts} (84%) rename index.js => index.ts (71%) rename music/{player.js => player.ts} (55%) rename schemas/{guild.js => guild.ts} (89%) rename schemas/{user.js => user.ts} (88%) delete mode 100644 selectMenus/general/help.js create mode 100644 selectMenus/general/help.ts create mode 100644 types/client.ts create mode 100644 types/command.ts rename www/{index.js => index.ts} (78%) rename www/routes/{commands.js => commands.ts} (51%) rename www/routes/{logo.js => logo.ts} (90%) rename www/static/commands/{index.js => index.ts} (83%) diff --git a/buttons/economy/resetBalance.js b/buttons/economy/resetBalance.ts similarity index 75% rename from buttons/economy/resetBalance.js rename to buttons/economy/resetBalance.ts index 4e6ee08..460bc39 100644 --- a/buttons/economy/resetBalance.js +++ b/buttons/economy/resetBalance.ts @@ -1,10 +1,12 @@ +import { Component } from "../../types/command"; + const userList = require("../../schemas/user"); module.exports = { run(client, interaction, args, guildData, userData) { userData.economy.wallet = 0; userData.economy.bank = 0; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { }); return { content: "Your balance has been reset!", disableOriginal: true }; } -} \ No newline at end of file +} as Component; \ No newline at end of file diff --git a/buttons/economy/resetLevel.js b/buttons/economy/resetLevel.ts similarity index 73% rename from buttons/economy/resetLevel.js rename to buttons/economy/resetLevel.ts index 42b30cf..cc55919 100644 --- a/buttons/economy/resetLevel.js +++ b/buttons/economy/resetLevel.ts @@ -1,9 +1,11 @@ +import { Component } from "../../types/command"; + const userList = require("../../schemas/user"); module.exports = { run(client, interaction, args, guildData, userData) { userData.level.xp = 0; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { }); return { content: "Your level has been reset!", disableOriginal: true }; } -} \ No newline at end of file +} as Component; \ No newline at end of file diff --git a/buttons/economy/search.js b/buttons/economy/search.ts similarity index 75% rename from buttons/economy/search.js rename to buttons/economy/search.ts index 91053d1..9eb7350 100644 --- a/buttons/economy/search.js +++ b/buttons/economy/search.ts @@ -1,16 +1,20 @@ +import { Component } from "../../types/command"; + const userList = require("../../schemas/user.js"); const { Random } = require("sussy-util"); module.exports = { name: "search", - cooldown: 60, + commandOptions: { + cooldown: 60 + }, async run(client, interaction, args, guildData, userData) { const amount = Random.randomInt(900, 1600); const current = userData.economy; current.wallet += amount; - userList.findByIdAndUpdate(userData._id, { economy: current }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { }); userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { }); return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; } -} \ No newline at end of file +} as Component; \ No newline at end of file diff --git a/buttons/general/support.js b/buttons/general/support.ts similarity index 91% rename from buttons/general/support.js rename to buttons/general/support.ts index 51f6b28..e38b4f8 100644 --- a/buttons/general/support.js +++ b/buttons/general/support.ts @@ -1,7 +1,9 @@ +import { Component } from "../../types/command"; + const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); module.exports = { - run(_client, interaction) { + run(client, interaction) { const choice = new ActionRowBuilder() .addComponents( new ButtonBuilder() @@ -23,4 +25,4 @@ module.exports = { ); return { content: 'If you can code, help us out on our Github, if not, maybe buy us some more processing power!', components: [choice] }; } -} +} as Component; diff --git a/buttons/music/play_pause.js b/buttons/music/play_pause.ts similarity index 71% rename from buttons/music/play_pause.js rename to buttons/music/play_pause.ts index 538c0e1..b3de31b 100644 --- a/buttons/music/play_pause.js +++ b/buttons/music/play_pause.ts @@ -1,5 +1,9 @@ +import { Component } from "../../types/command"; + module.exports = { - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, run(client, interaction) { let returnValue = client.player.pause(interaction); if (returnValue !== "The track is already paused") { @@ -9,4 +13,4 @@ module.exports = { } return returnValue; } -} +} as Component; diff --git a/commands/economy/balance.js b/commands/economy/balance.ts similarity index 71% rename from commands/economy/balance.js rename to commands/economy/balance.ts index a5d5bf6..bc7c070 100644 --- a/commands/economy/balance.js +++ b/commands/economy/balance.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Shows the balance of your money", aliases: ["bal"], @@ -6,4 +9,4 @@ module.exports = { return "You have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; } -} +} as Command; diff --git a/commands/economy/beg.js b/commands/economy/beg.ts similarity index 73% rename from commands/economy/beg.js rename to commands/economy/beg.ts index 12c2c4b..297905e 100644 --- a/commands/economy/beg.js +++ b/commands/economy/beg.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const userList = require("../../schemas/user"); const messages = require("../../resources/messages.json"); @@ -13,11 +16,17 @@ module.exports = { return "Not enough money to risk on losing"; const earned = Math.round(Math.random() * 400) - 200; userData.economy.wallet += earned; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { - message.channel.send(`<@${userData.userId}>` + " just levelled up!") + message.channel!.send(`<@${userData.userId}>` + " just levelled up!") } let valueRange = Math.ceil(Math.abs(earned / 100)); @@ -36,4 +45,4 @@ module.exports = { return messages.beg.veryGood.replace("{amount}", earned); } } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/economy/bet.js b/commands/economy/bet.ts similarity index 84% rename from commands/economy/bet.js rename to commands/economy/bet.ts index aadbe04..38d0b68 100644 --- a/commands/economy/bet.js +++ b/commands/economy/bet.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const userList = require("../../schemas/user"); const { EmbedBuilder } = require("discord.js"); const jobs = require("./resources/jobs.json").jobs; @@ -11,6 +14,7 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Casino") + // @ts-expect-error .setFooter(client.config.embedFooter(client)); if (!(IsSomething.isNumber(args[0]))) { @@ -36,7 +40,7 @@ module.exports = { switch (random) { case 0: - userData.economy.wallet -= args[0]; + userData.economy.wallet -= +args[0]; embed.addFields( { name: "You Lost!", @@ -56,8 +60,11 @@ module.exports = { ); break; } - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); } return { embeds: [embed] }; } -} +} as Command; diff --git a/commands/economy/deposit.js b/commands/economy/deposit.ts similarity index 78% rename from commands/economy/deposit.js rename to commands/economy/deposit.ts index ff8a9f4..8a69739 100644 --- a/commands/economy/deposit.js +++ b/commands/economy/deposit.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { IsSomething } = require("sussy-util"); const users = require("../../schemas/user"); @@ -9,7 +12,7 @@ module.exports = { { name: "amount", description: "max / Amount to deposit", - type: "STRING", + type: ApplicationCommandOptionType.String, required: true } ], @@ -32,7 +35,10 @@ module.exports = { moneys = +args[0]; } - users.findByIdAndUpdate(userInfo._id, { economy: current }, (err, data) => { }); + users.findByIdAndUpdate(userInfo._id, { economy: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); return `Deposited ${moneys} gold.`; } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/economy/job.js b/commands/economy/job.ts similarity index 82% rename from commands/economy/job.js rename to commands/economy/job.ts index 361388f..e95c820 100644 --- a/commands/economy/job.js +++ b/commands/economy/job.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const userList = require("../../schemas/user"); const { EmbedBuilder } = require("discord.js"); const jobs = require("./resources/jobs.json").jobs; @@ -6,18 +9,19 @@ const { IsSomething } = require("sussy-util"); module.exports = { description: "Panel which shows jobs", aliases: ["jobs"], - options: { + options: [{ name: "JobID", - type: "number", + type: ApplicationCommandOptionType.Integer, description: "ID of the job to switch to", required: false, - }, + }], run(client, _message, args, _guildData, userData) { - if (args[0] === undefined) { + if (args[0] === void 0) { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Jobs panel") + // @ts-expect-error .setFooter(client.config.embedFooter(client)) .addFields( { @@ -67,15 +71,18 @@ module.exports = { return "Provide a valid number as job ID"; if (currentID === +args[0]) return "You are already a " + jobs[currentID - 1].jobname; - if (args[0] <= 0 || args[0] > jobs.length) + if (+args[0] <= 0 || args[0] > jobs.length) return "Bad ID"; - if (Math.floor(userData.level.xp / 50) < (jobs[args[0] - 1].reqlevel)) { + if (Math.floor(userData.level.xp / 50) < (jobs[+args[0] - 1].reqlevel)) { return "Level too low for this job"; } userData.jobinfo.id = args[0]; - userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); return "Congratulations! You are now a " + jobs[userData.jobinfo.id - 1].jobname; } } -} +} as Command; diff --git a/commands/economy/level.js b/commands/economy/level.ts similarity index 84% rename from commands/economy/level.js rename to commands/economy/level.ts index 28c1557..ba9856f 100644 --- a/commands/economy/level.js +++ b/commands/economy/level.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { IsSomething } = require("sussy-util"); const { EmbedBuilder } = require("discord.js"); module.exports = { @@ -8,6 +11,7 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Level panel") + // @ts-expect-error .setFooter(client.config.embedFooter(client)); embed.addFields( @@ -25,4 +29,4 @@ module.exports = { return { embeds: [embed] }; } -} +} as Command; diff --git a/commands/economy/resetBalance.js b/commands/economy/resetBalance.ts similarity index 83% rename from commands/economy/resetBalance.js rename to commands/economy/resetBalance.ts index 53836ed..786f135 100644 --- a/commands/economy/resetBalance.js +++ b/commands/economy/resetBalance.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); module.exports = { @@ -9,6 +12,7 @@ module.exports = { .setTitle("Reset Balance") .setDescription("Are you sure you want to reset your balance?") .setColor(Colors.Red) + // @ts-expect-error .setFooter(client.config.embedFooter(client)); if (isInteraction) { @@ -20,7 +24,7 @@ module.exports = { .setStyle(ButtonStyle.Danger), ); - return { embeds: [embed], components: [row], disable: 60 }; + return { embeds: [embed], components: [row], timeout: 60 }; } else { const row = new ActionRowBuilder() .addComponents( @@ -29,7 +33,7 @@ module.exports = { .setLabel("Confirm") .setStyle(ButtonStyle.Danger), ); - return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], disable: 60 } }; + return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; } } -} +} as Command; diff --git a/commands/economy/resetLevel.js b/commands/economy/resetLevel.ts similarity index 82% rename from commands/economy/resetLevel.js rename to commands/economy/resetLevel.ts index c0f2e7d..af70dc5 100644 --- a/commands/economy/resetLevel.js +++ b/commands/economy/resetLevel.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); module.exports = { @@ -9,6 +12,7 @@ module.exports = { .setTitle("Reset Level") .setDescription("Are you sure you want to reset your level?") .setColor(Colors.Red) + // @ts-expect-error .setFooter(client.config.embedFooter(client)); if (isInteraction) { @@ -20,7 +24,7 @@ module.exports = { .setStyle(ButtonStyle.Danger), ); - return { embeds: [embed], components: [row] }; + return { embeds: [embed], components: [row], timeout: 60 }; } else { const row = new ActionRowBuilder() .addComponents( @@ -29,7 +33,7 @@ module.exports = { .setLabel("Confirm") .setStyle(ButtonStyle.Danger), ); - return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], disable: 60 } }; + return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; } } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/economy/search.js b/commands/economy/search.ts similarity index 95% rename from commands/economy/search.js rename to commands/economy/search.ts index d48e5c1..03097ea 100644 --- a/commands/economy/search.js +++ b/commands/economy/search.ts @@ -1,10 +1,15 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { StringUtil } = require("sussy-util"); const { EmbedBuilder, Colors, ActionRowBuilder, StringSelectMenuBuilder, SelectMenuOptionBuilder, ButtonStyle, ButtonBuilder } = require("discord.js"); const userList = require("../../schemas/user"); module.exports = { description: "Search in a few places for money.", - cooldown: 60, + commandOptions: { + cooldown: 60 + }, run: (_client, message, _args, _guildData, userData) => { const places = [ @@ -145,4 +150,4 @@ module.exports = { return { embeds: [embed], components: [actionRow] }; } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/economy/withdraw.js b/commands/economy/withdraw.ts similarity index 66% rename from commands/economy/withdraw.js rename to commands/economy/withdraw.ts index dcac185..477da52 100644 --- a/commands/economy/withdraw.js +++ b/commands/economy/withdraw.ts @@ -1,14 +1,17 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { IsSomething } = require("sussy-util"); const userList = require("../../schemas/user"); module.exports = { description: "Withdraw money from your bank account", aliases: ["with", "wth"], - options: { - name: "what shall be withdrawn from the bank", - type: "number", - description: "number of money that will be withdrawn from the bank", + options: [{ + name: "amount", + type: ApplicationCommandOptionType.String, + description: "Amount that will be withdrawn", required: true, - }, + }], run(client, message, args, guildData, userData, isSlashCommand) { let amount = args[0]; @@ -16,11 +19,14 @@ module.exports = { if (amount > userData.economy.bank) amount = userData.economy.bank; userData.economy.bank -= +amount; userData.economy.wallet += +amount; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); return amount + " withdrawn. You now have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; } else { return "Please specify an amount"; } } -} +} as Command; diff --git a/commands/economy/work.js b/commands/economy/work.ts similarity index 51% rename from commands/economy/work.js rename to commands/economy/work.ts index cfa9d60..ae9ec91 100644 --- a/commands/economy/work.js +++ b/commands/economy/work.ts @@ -1,22 +1,39 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const userList = require("../../schemas/user"); const jobs = require("./resources/jobs.json").jobs; module.exports = { description: "Work to earn money", aliases: ["wk"], - cooldown: 1800, + commandOptions: { + cooldown: 1800 + }, + options: [{ + name: "job", + type: ApplicationCommandOptionType.String, + description: "Job you want to work as", + required: true, + }], run(client, message, args, guildData, userData, isSlashCommand) { if (userData.economy) { let earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); userData.economy.wallet += earned; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); userData.level.xp += 5; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err, data) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); if (!(Math.floor(userData.level.xp / 50) === (Math.floor((userData.level.xp - 5) / 50)))) { - message.channel.send(`<@${userData.userId}>` + " just levelled up!") + message!.channel!.send(`<@${userData.userId}>` + " just levelled up!") } - return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", success: [this] }; + return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", setCooldown: [this] }; } } -} +} as Command; diff --git a/commands/games/coinflip.js b/commands/games/coinflip.ts similarity index 62% rename from commands/games/coinflip.js rename to commands/games/coinflip.ts index 5cd6646..3d8e43e 100644 --- a/commands/games/coinflip.js +++ b/commands/games/coinflip.ts @@ -1,23 +1,26 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { - aliases: ["flip", "coin", "skyrim"], + aliases: ["flip", "coin"], description: 'flips a coin', - options: { + options: [{ name: "headsTails", - type: `STRING`, + type: ApplicationCommandOptionType.String, description: "select heads or tails", required: false, - }, + }], run(client, message, args, guildData, userData, isSlashCommand) { const coinArray = ["heads", "tails"]; let numberThrow = Math.floor(Math.random() * 2); if (!(args[0] === `heads`) && !(args[0] === 'tails')) { - return coinArray[numberThrow]; //fluorine coding convention 🤮 + return coinArray[numberThrow]; } - message.channel.send(coinArray[numberThrow]); + message!.channel!.send(coinArray[numberThrow]); if (args[0] === coinArray[numberThrow]) { return "You are victorious!"; } return "You are a loser!"; } -} +} as Command; diff --git a/commands/games/numberguess.js b/commands/games/numberguess.ts similarity index 63% rename from commands/games/numberguess.js rename to commands/games/numberguess.ts index 2374b29..b265baf 100644 --- a/commands/games/numberguess.js +++ b/commands/games/numberguess.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { IsSomething } = require("sussy-util"); module.exports = { aliases: ["number", "guess"], @@ -5,20 +8,20 @@ module.exports = { options: [ { name: "number", - type: "number", + type: ApplicationCommandOptionType.Number, description: "the specified number", required: true, }, { name: "guess", - type: "number", + type: ApplicationCommandOptionType.Number, description: "the guessed number", required: true, } ], run(client, message, args, guildData, userData, isSlashCommand) { - if (args[0] === undefined || args[0] === `` || args[1] === undefined || args[1] === ``) { + if (args[0] === void 0 || args[0] === `` || args[1] === void 0 || args[1] === ``) { return "Please specify two numbers"; } if (!(IsSomething.isNumber(args[0])) || !(IsSomething.isNumber(args[1]))) { @@ -27,14 +30,12 @@ module.exports = { if (args[1] > args[0]) { return "First number needs to be larger than the second" } - const number = Math.round(Math.random() * args[0] - 1) + 1; - message.channel.send("Number was generated! The number is: " + number); + const number = Math.round(Math.random() * +args[0] - 1) + 1; + message!.channel!.send("Number was generated! The number is: " + number); if (number === +(args[1])) { return "Your number is correct!"; - } - return "Your number is false!"; - + } else + return "Your number is false!"; } - -} +} as Command; \ No newline at end of file diff --git a/commands/general/help.js b/commands/general/help.ts similarity index 78% rename from commands/general/help.js rename to commands/general/help.ts index 0faf421..dbceebb 100644 --- a/commands/general/help.js +++ b/commands/general/help.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, StringSelectMenuBuilder } = require("discord.js"); const { StringUtil } = require("sussy-util"); @@ -11,7 +14,7 @@ module.exports = { { name: "query", description: "name of the command", - type: "STRING", + type: ApplicationCommandOptionType.String, required: false, } ], @@ -25,13 +28,14 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Help panel") + // @ts-expect-error .setFooter(client.config.embedFooter(client)); - if (commandName === undefined || commandName.length === 0) { + if (commandName === void 0 || commandName.length === 0) { embed .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); - fs.readdirSync(`${__dirname}/../`).forEach((d) => { + fs.readdirSync(`${__dirname}/../`).forEach((d: any) => { embed.addFields({ name: StringUtil.capitalize(d), value: "Type `" + client.config.prefix + "help " + d + "` to see more information", @@ -42,7 +46,7 @@ module.exports = { const cmd = client.commands.get(`command:${commandName}`) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); - if (cmd === undefined) { + if (cmd === void 0) { return "No command found for: `" + commandName + "`"; } @@ -65,13 +69,14 @@ module.exports = { inline: true }, { - name: cmd.aliases?.length > 1 ? "Aliases" : "Alias", - value: cmd.aliases?.length > 0 ? cmd.aliases.join(", ") : "None", + name: cmd.aliases?.length! > 1 ? "Aliases" : "Alias", + value: cmd.aliases?.length! > 0 ? cmd.aliases!.join(", ") : "None", inline: true }, { name: "Cooldown", - value: cmd.cooldown ? `${cmd.cooldown}seconds` : "None", + // @ts-expect-error + value: cmd.commandOptions?.defaultReturn?.cooldown ? `${cmd.cooldown}seconds` : "None", inline: true } ); @@ -83,4 +88,4 @@ module.exports = { return { embeds: [embed] }; } } -} +} as Command; diff --git a/commands/general/info.js b/commands/general/info.ts similarity index 84% rename from commands/general/info.js rename to commands/general/info.ts index 06fb98c..e81ab4a 100644 --- a/commands/general/info.js +++ b/commands/general/info.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, version: discordjsVersion, Colors } = require("discord.js"); const ms = require("@parade/pretty-ms"); @@ -9,7 +12,7 @@ module.exports = { embeds: [new EmbedBuilder() .setColor(Colors.Red) .setTitle(`${client.user.username} v${require("../../package.json")["version"]}`) - .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) + .setThumbnail(client.user.displayAvatarURL()) .setURL("https://github.com/plastik-flasche/SUS-Bot") .addFields( { name: "Uptime", value: `${ms(client.uptime)}`, inline: true }, @@ -17,14 +20,15 @@ module.exports = { { name: "Discord.js", value: `${discordjsVersion}`, inline: true }, { name: "Guild Count", value: `${client.guilds.cache.size} guilds`, inline: true }, { name: "User Count", value: `${client.users.cache.size} users`, inline: true }, - { name: "Commands", value: `${client.commands.filter(e => e.name.startsWith("command:") && !e.ignore).size} commands`, inline: true }, + { name: "Commands", value: `${client.commands.filter(e => e.name!.startsWith("command:") && !e.ignore).size} commands`, inline: true }, { name: "Memory", value: `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB RSS\n${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB Heap`, inline: true }, { name: "Cached Data", value: `${client.users.cache.size} users\n${client.emojis.cache.size} emojis`, inline: true }, { name: "Node", value: `${process.version} on ${process.platform} ${process.arch}`, inline: true } ) + // @ts-expect-error .setFooter(client.config.embedFooter(client)) .setTimestamp(new Date()) ] }; } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/general/invite.js b/commands/general/invite.js deleted file mode 100644 index 7635988..0000000 --- a/commands/general/invite.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - description: "Sends the invite link of the server", - - async run(client, message, args, guildData, userData, isSlashCommand) { - const invite = await message.channel.createInvite({ unique: true, temporary: true }); - return "https://discord.gg/" + invite.code; - } -} diff --git a/commands/general/invite.ts b/commands/general/invite.ts new file mode 100644 index 0000000..658840e --- /dev/null +++ b/commands/general/invite.ts @@ -0,0 +1,15 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +module.exports = { + description: "Sends the invite link of the server", + commandOptions: { + guildOnly: true, + }, + + async run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error // It can't even get to this point if it's not a guild + const invite = await message.channel!.createInvite({ unique: true, temporary: true }); + return "https://discord.gg/" + invite.code; + } +} as Command; diff --git a/commands/general/inviteBot.js b/commands/general/inviteBot.ts similarity index 71% rename from commands/general/inviteBot.js rename to commands/general/inviteBot.ts index 470955d..81858bb 100644 --- a/commands/general/inviteBot.js +++ b/commands/general/inviteBot.ts @@ -1,7 +1,10 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Sends the invite link of the bot", async run(client, message, args, guildData, userData, isSlashCommand) { return { content: "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands" }; } -} +} as Command; diff --git a/commands/general/serverinfo.js b/commands/general/serverinfo.ts similarity index 60% rename from commands/general/serverinfo.js rename to commands/general/serverinfo.ts index 16a849f..13cf8c4 100644 --- a/commands/general/serverinfo.js +++ b/commands/general/serverinfo.ts @@ -1,3 +1,6 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -7,13 +10,13 @@ module.exports = { const sEmbed = new EmbedBuilder() .setColor(Colors.Red) .setTitle("Server Info") - .setThumbnail(message.guild.iconURL()) - .setAuthor({ name: `${message.guild.name} Info`, iconUrl: message.guild.iconURL() }) - .addFields({ name: "***Guild Name:***", value: `${message.guild.name}`, inline: true }, - { name: "***Guild Owner:***", value: `<@!${message.guild.ownerId}>`, inline: true }, - { name: "***Member Count:***", value: `${message.guild.memberCount}`, inline: true }) + .setThumbnail(message.guild!.iconURL()) + .setAuthor({ name: `${message.guild!.name} Info`, iconUrl: message.guild!.iconURL() }) + .addFields({ name: "***Guild Name:***", value: `${message.guild!.name}`, inline: true }, + { name: "***Guild Owner:***", value: `<@!${message.guild!.ownerId}>`, inline: true }, + { name: "***Member Count:***", value: `${message.guild!.memberCount}`, inline: true }) .setTimestamp(new Date()); return { embeds: [sEmbed] }; } -} +} as Command; diff --git a/commands/general/userinfo.js b/commands/general/userinfo.ts similarity index 71% rename from commands/general/userinfo.js rename to commands/general/userinfo.ts index a173942..f964a51 100644 --- a/commands/general/userinfo.js +++ b/commands/general/userinfo.ts @@ -1,10 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { EmbedBuilder, Colors } = require('discord.js'); module.exports = { description: "Displays information about the current user.", run(client, message, args) { - const user = message.mentions.users.first() || client.users.cache.get(args[0]) || message.author; + // @ts-expect-error // yes, it does exist! + const user = message.mentions!.users.first() || client.users.cache.get(args[0]) || message.author; return { embeds: [new EmbedBuilder() @@ -18,11 +22,13 @@ module.exports = { { name: "Bot", value: `${user.bot ? "Yes" : "No"}`, inline: true }, { name: "Verified", value: user.verified ? "Yes" : "No", inline: true }, { name: "Created", value: user.createdAt.toDateString(), inline: true }, - { name: "Joined", value: new Date(message.guild.members.cache.get(user.id).joinedTimestamp).toDateString(), inline: true }, + // @ts-expect-error // WTF is this error? + { name: "Joined", value: new Date(message.guild.members.cache.get(user.id)!.joinedTimestamp).toDateString(), inline: true }, ) .setTimestamp(new Date()) + // @ts-expect-error .setFooter(client.config.embedFooter(client)) ] }; } -} \ No newline at end of file +} as Command; \ No newline at end of file diff --git a/commands/moderation/clear.js b/commands/moderation/clear.js deleted file mode 100644 index aeab626..0000000 --- a/commands/moderation/clear.js +++ /dev/null @@ -1,80 +0,0 @@ -const { ManageMessages } = require("../../enums/permissionBitField"); -const { ManageMessages: manageMsgs } = require("../../enums/permissionStrings"); - -module.exports = { - description: "Clears the last n messages", - - options: [ - { - name: "query", - type: "NUMBER", - description: "amount of messages to clear", - required: true - } - ], - - default_member_permissions: manageMsgs, - - async run(client, message, args, guildData, userData, isSlashCommand) { - const amount = parseInt(args[0]); - - if (args[0] === "all") { - clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { - if (isSlashCommand) - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - else - message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - }).catch(err => { - if (isSlashCommand) - message.followUp(err); - else - message.channel.send - }); - - return null; - } else if (isNaN(amount)) return "Please provide a number as the first argument."; - - if (amount <= 0) return "Number must be at least 1."; - - clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { - if (isSlashCommand) - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - else - message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - }).catch(err => { - if (isSlashCommand) - message.followUp(err); - else - message.channel.send(err); - }); - - return null; - } -} - -function clearMessages(message, amount, isSlashCommand = false) { - return new Promise(async (resolve, reject) => { - let deletedMessagesCount = isSlashCommand ? 0 : -1; - while (deletedMessagesCount < amount) { - const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); - const deletedMessages = await message.channel.bulkDelete(deleteThisTime, true) - .catch(err => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === undefined || deletedMessages.size === 0) break; - deletedMessagesCount += deletedMessages.size; - } - resolve(deletedMessagesCount); - }); -} - -function clearAllMessages(message, isSlashCommand = false) { - return new Promise(async (resolve, reject) => { - let deletedMessagesCount = isSlashCommand ? 0 : -1; - while (true) { - const deletedMessages = await message.channel.bulkDelete(100, true) - .catch(err => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === undefined || deletedMessages.size === 0) break; - deletedMessagesCount += deletedMessages.size; - } - resolve(deletedMessagesCount); - }); -} \ No newline at end of file diff --git a/commands/moderation/clear.ts b/commands/moderation/clear.ts new file mode 100644 index 0000000..31991a8 --- /dev/null +++ b/commands/moderation/clear.ts @@ -0,0 +1,89 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType, CommandInteraction, Message } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; + +module.exports = { + description: "Clears the last n messages", + + options: [ + { + name: "query", + type: ApplicationCommandOptionType.Integer, + description: "amount of messages to clear", + required: true + } + ], + + default_member_permissions: permissionStrings.ManageMessages, + + async run(client, message, args, guildData, userData, isSlashCommand) { + const amount = parseInt(args[0]); + + if (args[0] === "all") { + clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME below + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch((err: string) => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME below + message.followUp(err); + else + message.channel!.send(err); + }); + + return null; + } else if (isNaN(amount)) return "Please provide a number as the first argument."; + + if (amount <= 0) return "Number must be at least 1."; + + clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { + // FIXME: isSlashCommand is kinda unnecessary here when working with TypeScript cause we can check if message is a CommandInteraction + if (isSlashCommand) + // @ts-expect-error // look at the FIXME above + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch(err => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME above + message.followUp(err); + else + message.channel!.send(err); + }); + + return null; + } +} as Command; + +function clearMessages(message: Message | CommandInteraction, amount: number, isSlashCommand = false) { + return new Promise(async (resolve, reject) => { + let deletedMessagesCount = isSlashCommand ? 0 : -1; + while (deletedMessagesCount < amount) { + const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); + // @ts-expect-error // I just can't be bothered to fix this + const deletedMessages = await message.channel!.bulkDelete(deleteThisTime, true) + .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === void 0 || deletedMessages.size === 0) break; + deletedMessagesCount += deletedMessages.size; + } + resolve(deletedMessagesCount); + }); +} + +function clearAllMessages(message: Message | CommandInteraction, isSlashCommand = false) { + return new Promise(async (resolve, reject) => { + let deletedMessagesCount = isSlashCommand ? 0 : -1; + while (true) { + // @ts-expect-error // I just can't be bothered to fix this + const deletedMessages = await message.channel!.bulkDelete(100, true) + .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === void 0 || deletedMessages.size === 0) break; + deletedMessagesCount += deletedMessages.size; + } + resolve(deletedMessagesCount); + }); +} \ No newline at end of file diff --git a/commands/moderation/lock.js b/commands/moderation/lock.ts similarity index 54% rename from commands/moderation/lock.js rename to commands/moderation/lock.ts index 4cb332f..f7cc0f3 100644 --- a/commands/moderation/lock.js +++ b/commands/moderation/lock.ts @@ -1,5 +1,8 @@ -const { ManageChannels, SendMessages } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionBitField from "../../enums/permissionBitField"; +import permissionStrings from "../../enums/permissionStrings"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -9,30 +12,32 @@ module.exports = { options: [ { name: "channel", - type: "CHANNEL", + type: ApplicationCommandOptionType.Channel, description: "The channel you want to lock", required: true } ], - default_member_permissions: ManageChannel, + default_member_permissions: permissionStrings.ManageChannels, run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) channel = message.channel; + channel ||= message.channel; - if (!channel.permissionsFor(message.guild.roles.everyone).has(SendMessages)) + if (!channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) return "Channel is already locked"; - channel.permissionOverwrites.edit(message.guild.roles.everyone, { SEND_MESSAGES: false }); + channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: false }); const embed = new EmbedBuilder() .setTitle("Channel Updates") .setDescription(`<#${channel.id}> in now locked!`) .setColor(Colors.Red) + // @ts-expect-error .setFooter(client.config.embedFooter(client)) .setTimestamp(new Date()) return { embeds: [embed] }; } -} +} as Command; diff --git a/commands/moderation/nickname.js b/commands/moderation/nickname.ts similarity index 65% rename from commands/moderation/nickname.js rename to commands/moderation/nickname.ts index 68461d0..c57ed5c 100644 --- a/commands/moderation/nickname.js +++ b/commands/moderation/nickname.ts @@ -1,5 +1,7 @@ -const { ManageNicknames } = require("../../enums/permissionBitField"); -const { ManageNicknames: mngNick } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; module.exports = { aliases: ["nick"], @@ -8,30 +10,31 @@ module.exports = { options: [ { name: "user", - type: "USER", + type: ApplicationCommandOptionType.User, description: "user you want to change the nickname of", required: true, }, { name: "nickname", - type: "string", + type: ApplicationCommandOptionType.String, description: "nickname to change to", required: true, } ], - default_member_permissions: mngNick, + default_member_permissions: permissionStrings.ManageNicknames, async run(client, message, args, guildData, userData, isSlashCommand) { - let mentionedMember = message.mentions.members.first() || message.guild.members.cache.get(args[0]); + // @ts-expect-error + let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); let nickName; - if (mentionedMember === undefined) { + if (mentionedMember === void 0) { nickName = args.slice(0).join(" "); mentionedMember = message.member; } else nickName = args.slice(1).join(" "); - if (nickName === undefined) return "Please provide a nickname for me to change this users nickname"; + if (nickName === void 0) return "Please provide a nickname for me to change this users nickname"; try { const username = mentionedMember.nickname || mentionedMember.user.username; @@ -41,4 +44,4 @@ module.exports = { return `I do not have the required permissions to to set ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; } } -} +} as Command; diff --git a/commands/moderation/prepare.js b/commands/moderation/prepare.ts similarity index 55% rename from commands/moderation/prepare.js rename to commands/moderation/prepare.ts index 9ebf711..eab0dc3 100644 --- a/commands/moderation/prepare.js +++ b/commands/moderation/prepare.ts @@ -1,16 +1,22 @@ +import { Command } from "../../types/command"; +import Client from "../../types/client"; +import { ApplicationCommandOptionType, CommandInteraction, Message } from "discord.js"; + const { EmbedBuilder } = require("discord.js"); -const registering = (client, second) => { - if (!second.member.permissions.has("ADMINISTRATOR")) return new EmbedBuilder() +const registering = (client: Client, message: CommandInteraction | Message) => { + // @ts-expect-error + if (!message.member!.permissions.has("ADMINISTRATOR")) return new EmbedBuilder() .setTitle("Failed to create slash-commands") .setDescription("You do not have permissions to create slash-commands"); const embed = new EmbedBuilder() .setTitle("Success") - client.commands.forEach(command => { + client.commands.forEach((command: Command) => { if (command.name === "prepare") return; - second.guild.commands?.create(command).catch(error => { + // @ts-expect-error // cause name can't be undefined, look at index.js + message.guild!.commands?.create(command).catch((error: Error) => { return new EmbedBuilder() .setTitle("Failed to create slash-commands") .setDescription(error.toString()); @@ -27,4 +33,4 @@ module.exports = { const embed = registering(client, message); return { embeds: [embed] }; } -} +} as Command; diff --git a/commands/moderation/remove-nickname.js b/commands/moderation/remove-nickname.ts similarity index 65% rename from commands/moderation/remove-nickname.js rename to commands/moderation/remove-nickname.ts index 511544d..23505bf 100644 --- a/commands/moderation/remove-nickname.js +++ b/commands/moderation/remove-nickname.ts @@ -1,5 +1,8 @@ -const { ManageNicknames } = require("../../enums/permissionBitField"); -const { ManageNicknames: mngNick } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionBitField from "../../enums/permissionBitField"; +import permissionStrings from "../../enums/permissionStrings"; module.exports = { aliases: ["remove-nick", "reset-nick", "reset-nickname", "un-nick", "un-nickname", "unnick", "unnickname", "removenick", "removenickname"], @@ -8,18 +11,18 @@ module.exports = { options: [ { name: "user", - type: "USER", + type: ApplicationCommandOptionType.User, description: "User you want to change the nickname of", required: true, } ], - default_member_permissions: mngNick, + default_member_permissions: permissionStrings.ManageNicknames, async run(client, message, args, guildData, userData, isSlashCommand) { - let mentionedMember = message.mentions.members.first() || message.guild.members.cache.get(args[0]); - if (mentionedMember === undefined) - mentionedMember = message.member; + // @ts-expect-error + let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); + mentionedMember ||= message.member; try { const username = mentionedMember.nickname || mentionedMember.user.username; @@ -29,4 +32,4 @@ module.exports = { return `I do not have the required permissions to to reset ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; } } -} +} as Command; diff --git a/commands/moderation/set-counter-channel.js b/commands/moderation/set-counter-channel.ts similarity index 54% rename from commands/moderation/set-counter-channel.js rename to commands/moderation/set-counter-channel.ts index b50ecfd..04f0410 100644 --- a/commands/moderation/set-counter-channel.js +++ b/commands/moderation/set-counter-channel.ts @@ -1,6 +1,8 @@ -const { ManageChannels } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const guilds = require("../../schemas/guild"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; +import guilds from "../../schemas/guild"; module.exports = { ignore: true, //TODO: Needs fix ASAP @@ -10,21 +12,25 @@ module.exports = { options: [ { name: "channel", - type: "CHANNEL", + type: ApplicationCommandOptionType.Channel, description: "The channel you want to set as counter channel.", required: true } ], - default_member_permissions: ManageChannel, + default_member_permissions: permissionStrings.ManageChannels, async run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) channel = message.channel; + if (channel === void 0) channel = message.channel; const current = guildData.channels; current.counter = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err, data) => { }); + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); return `Set counter channel to ${channel.toString()}`; } -} +} as Command; diff --git a/commands/moderation/set-goodbye-channel.js b/commands/moderation/set-goodbye-channel.ts similarity index 52% rename from commands/moderation/set-goodbye-channel.js rename to commands/moderation/set-goodbye-channel.ts index e28c805..74209b7 100644 --- a/commands/moderation/set-goodbye-channel.js +++ b/commands/moderation/set-goodbye-channel.ts @@ -1,6 +1,8 @@ -const { ManageChannels } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const guilds = require("../../schemas/guild"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; +import guilds from "../../schemas/guild"; module.exports = { ignore: true, //TODO: Needs fix ASAP @@ -10,21 +12,25 @@ module.exports = { options: [ { name: "channel", - type: "CHANNEL", + type: ApplicationCommandOptionType.Channel, description: "The channel you want to set as goodbye channel.", required: true } ], - default_member_permissions: ManageChannel, + default_member_permissions: permissionStrings.ManageChannels, async run(client, message, args, guildData, userData, isSlashCommand) { - const channel = global.functions.getChannelFromMention(message.guild, args[0]); + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; const current = guildData.channels; current.goodbye = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err, data) => { }); + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); return `Set goodbye channel to ${channel.toString()}`; } -} +} as Command; diff --git a/commands/moderation/set-welcome-channel.js b/commands/moderation/set-welcome-channel.js deleted file mode 100644 index d3a5238..0000000 --- a/commands/moderation/set-welcome-channel.js +++ /dev/null @@ -1,30 +0,0 @@ -const { ManageChannels } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); -const guilds = require("../../schemas/guild"); - -module.exports = { - ignore: true, //TODO: Needs fix ASAP - description: "Sets the welcome channel", - aliases: ["swc"], - - options: [ - { - name: "channel", - type: "CHANNEL", - description: "The channel you want to set as welcome channel.", - required: true - } - ], - - default_member_permissions: ManageChannel, - - async run(client, message, args, guildData, userData, isSlashCommand) { - const channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) channel = message.channel; - const current = guildData.channels; - current.welcome = channel.id; - - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err, data) => { }); - return `Set welcome channel to ${channel.toString()}`; - } -} diff --git a/commands/moderation/set-welcome-channel.ts b/commands/moderation/set-welcome-channel.ts new file mode 100644 index 0000000..ddde3c8 --- /dev/null +++ b/commands/moderation/set-welcome-channel.ts @@ -0,0 +1,36 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; +import guilds from "../../schemas/guild"; + +module.exports = { + ignore: true, //TODO: Needs fix ASAP + description: "Sets the welcome channel", + aliases: ["swc"], + + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to set as welcome channel.", + required: true + } + ], + + default_member_permissions: permissionStrings.ManageChannels, + + async run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + channel ||= message.channel; + const current = guildData.channels; + current.welcome = channel.id; + + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return `Set welcome channel to ${channel.toString()}`; + } +} as Command; diff --git a/commands/moderation/slowmode.js b/commands/moderation/slowmode.ts similarity index 70% rename from commands/moderation/slowmode.js rename to commands/moderation/slowmode.ts index 3bb5ad8..19eea03 100644 --- a/commands/moderation/slowmode.js +++ b/commands/moderation/slowmode.ts @@ -1,6 +1,8 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + const { IsSomething } = require("sussy-util"); -const { ManageChannels } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); +import permissionStrings from "../../enums/permissionStrings"; module.exports = { description: "Sets the slowmode of the current channel", @@ -8,25 +10,26 @@ module.exports = { option: [ { name: "channel", - type: "CHANNEL", + type: ApplicationCommandOptionType.Channel, description: "The channel you want to set the slowmode of", required: true }, { name: "timeout", - type: "NUMBER", + type: ApplicationCommandOptionType.Integer, description: "The timeout you want in seconds", required: false } ], - default_member_permissions: ManageChannel, + default_member_permissions: permissionStrings.ManageChannels, run(client, message, args, guildData, userData, isSlashCommand) { let rate; + // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) { + if (channel === void 0) { channel = message.channel; rate = args[0]; } else rate = args[1]; @@ -39,4 +42,4 @@ module.exports = { channel.setRateLimitPerUser(+rate); return `The slowmode of ${channel.toString()} was set to ${rate} seconds.`; } -} +} as Command; diff --git a/commands/moderation/tempban.js b/commands/moderation/tempban.ts similarity index 58% rename from commands/moderation/tempban.js rename to commands/moderation/tempban.ts index 719c8c1..89495fc 100644 --- a/commands/moderation/tempban.js +++ b/commands/moderation/tempban.ts @@ -1,5 +1,7 @@ -const { BanMembers } = require("../../enums/permissionBitField"); -const { BanMembers: banMbs } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; // TODO: write temp ban command module.exports = { @@ -10,22 +12,22 @@ module.exports = { options: [ { name: "user", - type: "USER", + type: ApplicationCommandOptionType.User, description: "User you want to tempban", required: true, }, { name: "days", - type: "NUMBER", + type: ApplicationCommandOptionType.Integer, description: "The amount of days you want to ban the user", required: true } ], - default_member_permissions: banMbs, + default_member_permissions: permissionStrings.BanMembers, run(client, message, args, guildData, userData, isSlashCommand) { } -} +} as Command; diff --git a/commands/moderation/unban.js b/commands/moderation/unban.ts similarity index 61% rename from commands/moderation/unban.js rename to commands/moderation/unban.ts index 1861426..202f4ca 100644 --- a/commands/moderation/unban.js +++ b/commands/moderation/unban.ts @@ -1,5 +1,7 @@ -const { BanMembers } = require("../../enums/permissionBitField"); -const { BanMembers: banMbs } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionStrings from "../../enums/permissionStrings"; module.exports = { ignore: true, @@ -8,29 +10,29 @@ module.exports = { options: [ { name: "user", - type: "USER", + type: ApplicationCommandOptionType.User, description: "User you want to unban", required: true, } ], - default_member_permissions: banMbs, + default_member_permissions: permissionStrings.BanMembers, async run(client, message, args, guildData, userData, isSlashCommand) { - if (args[0] === undefined) + if (args[0] === void 0) return "Please Give Me Member ID That You Want To Unban!"; - const bans = await message.guild.bans.fetch(); + const bans = await message.guild!.bans.fetch(); const member = bans.find(b => b.user.username.toLowerCase() === args[0].toLocaleLowerCase()) || bans.get(args[0]) || bans.find(bm => bm.user.tag.toLowerCase() === args[0].toLocaleLowerCase()); - if (member === undefined) + if (member === void 0) return "Please Give Valid Member ID Or Member Is Not Banned!"; try { - await message.guild.members.unban(member.user.id, Reason); - return `Unbanned <@!${args[0]}>. With reason: ${args.slice(1) || "No Reason Provided!"}`; + await message.guild!.members.unban(member.user.id, args[1] || "No Reason Provided!"); + return `Unbanned <@!${args[0]}>. With reason: ${args[1] || "No Reason Provided!"}`; } catch (error) { return "I Can't Unban That Member Maybe Member Is Not Banned Or Some Error!"; } } -} +} as Command; diff --git a/commands/moderation/unlock.js b/commands/moderation/unlock.ts similarity index 54% rename from commands/moderation/unlock.js rename to commands/moderation/unlock.ts index 944277f..26cb49e 100644 --- a/commands/moderation/unlock.js +++ b/commands/moderation/unlock.ts @@ -1,5 +1,8 @@ -const { ManageChannels, SendMessages } = require("../../enums/permissionBitField"); -const { ManageChannels: ManageChannel } = require("../../enums/permissionStrings"); +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +import permissionBitField from "../../enums/permissionBitField"; +import permissionStrings from "../../enums/permissionStrings"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -9,30 +12,32 @@ module.exports = { options: [ { name: "channel", - type: "CHANNEL", + type: ApplicationCommandOptionType.Channel, description: "The channel you want to unlock", required: true } ], - default_member_permissions: ManageChannel, + default_member_permissions: permissionStrings.ManageChannels, run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) channel = message.channel; + channel ||= message.channel; - if (channel.permissionsFor(message.guild.roles.everyone).has(SendMessages)) + if (channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) return "Channel isn't locked"; - channel.permissionOverwrites.edit(message.guild.roles.everyone, { SEND_MESSAGES: true }); + channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: true }); const embed = new EmbedBuilder() .setTitle("Channel Updates") .setDescription(`<#${channel.id}> is now unlocked!`) .setColor(Colors.Red) + // @ts-expect-error .setFooter(client.config.embedFooter(client)) .setTimestamp(new Date()) return { embeds: [embed] }; } -} +} as Command; diff --git a/commands/music/clearQueue.js b/commands/music/clearQueue.ts similarity index 50% rename from commands/music/clearQueue.js rename to commands/music/clearQueue.ts index aadb550..a045757 100644 --- a/commands/music/clearQueue.js +++ b/commands/music/clearQueue.ts @@ -1,8 +1,13 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Clears the song queue.", - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, run(client, message, args, guildData, userData, isSlashCommand) { return client.player.clearQueue(message); } -} +} as Command; diff --git a/commands/music/loop.js b/commands/music/loop.ts similarity index 54% rename from commands/music/loop.js rename to commands/music/loop.ts index 87f0de8..443fb0e 100644 --- a/commands/music/loop.js +++ b/commands/music/loop.ts @@ -1,9 +1,13 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Loops the current queue.", aliases: ["repeat"], - connectedToSameVoiceChannel: true, - + commandOptions: { + connectedToSameVC: true + }, run(client, message, args, guildData, userData, isSlashCommand) { return client.player.toggleLoop(message); }, -} +} as Command; diff --git a/commands/music/nowPlaying.js b/commands/music/nowPlaying.js deleted file mode 100644 index 524f71c..0000000 --- a/commands/music/nowPlaying.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - description: "Shows the current song", - aliases: ["current"], - connectedToSameVoiceChannel: true, - - async run(client, message, args, guildData, userData, isSlashCommand) { - if (client.player.getQueue(message.guild.id) === undefined) { - return "There is no queue"; - } - - const current = client.player.getCurrent(message.guild.id); - - if (current === undefined) { - return "Currently not playing anything"; - } - - return `Now Playing: **${current.title}**\n`; - } -} diff --git a/commands/music/nowPlaying.ts b/commands/music/nowPlaying.ts new file mode 100644 index 0000000..38ee517 --- /dev/null +++ b/commands/music/nowPlaying.ts @@ -0,0 +1,24 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + +module.exports = { + description: "Shows the current song", + aliases: ["current"], + commandOptions: { + connectedToSameVC: true + }, + + async run(client, message, args, guildData, userData, isSlashCommand) { + if (client.player.getQueue(message.guild!.id) === void 0) { + return "There is no queue"; + } + + const current = client.player.getCurrent(message.guild!.id); + + if (current === void 0) { + return "Currently not playing anything"; + } + + return `Now Playing: **${current.title}**\n`; + } +} as Command; diff --git a/commands/music/pause.js b/commands/music/pause.ts similarity index 52% rename from commands/music/pause.js rename to commands/music/pause.ts index e07a60b..0ac1939 100644 --- a/commands/music/pause.js +++ b/commands/music/pause.ts @@ -1,9 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { aliases: [], description: "Pauses the current song", - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, run(client, message, args, guildData, userData, isSlashCommand) { return client.player.pause(message); } -} +} as Command; diff --git a/commands/music/play.js b/commands/music/play.ts similarity index 62% rename from commands/music/play.js rename to commands/music/play.ts index 7a20bee..070284d 100644 --- a/commands/music/play.js +++ b/commands/music/play.ts @@ -1,19 +1,23 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Adds a song to the queue", aliases: ["p"], - connectedToVoiceChannel: true, + connectedToVC: true, options: [ { name: "query", - type: "STRING", + type: ApplicationCommandOptionType.String, description: "Link/Name of track to play", required: true } ], async run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error // cause it's getting caught anyway try { message.suppressEmbeds(true); } catch (e) { } return client.player.addTrack(message, args); } -} +} as Command; diff --git a/commands/music/queue.js b/commands/music/queue.ts similarity index 70% rename from commands/music/queue.js rename to commands/music/queue.ts index 50110a4..60e38ca 100644 --- a/commands/music/queue.js +++ b/commands/music/queue.ts @@ -1,12 +1,17 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Shows the song queue", aliases: ["q"], - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, async run(client, message, args, guildData, userData, isSlashCommand) { - const playerInfo = client.player.getQueue(message.guild.id); + const playerInfo = client.player.getQueue(message.guild!.id); - if (playerInfo === undefined) { + if (playerInfo === void 0) { return "There are no songs in the queue"; } @@ -22,4 +27,4 @@ module.exports = { return (currentString + queueString); } -} +} as Command; diff --git a/commands/music/resume.js b/commands/music/resume.ts similarity index 52% rename from commands/music/resume.js rename to commands/music/resume.ts index 103ddc4..3f297fc 100644 --- a/commands/music/resume.js +++ b/commands/music/resume.ts @@ -1,9 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { aliases: ["unpause"], description: "Resumes playing", - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, run(client, message, args, guildData, userData, isSlashCommand) { return client.player.resume(message); } -} +} as Command; diff --git a/commands/music/shuffle.js b/commands/music/shuffle.ts similarity index 53% rename from commands/music/shuffle.js rename to commands/music/shuffle.ts index eee528a..9fedc34 100644 --- a/commands/music/shuffle.js +++ b/commands/music/shuffle.ts @@ -1,9 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Shuffles the queue", aliases: ["mix"], - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, async run(client, message, args, guildData, userData, isSlashCommand) { return client.player.shuffle(message); } -} +} as Command; diff --git a/commands/music/skip.js b/commands/music/skip.ts similarity index 60% rename from commands/music/skip.js rename to commands/music/skip.ts index cf15230..c007d2a 100644 --- a/commands/music/skip.js +++ b/commands/music/skip.ts @@ -1,9 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Skips current track", aliases: ["next"], - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, run(client, message, args, guildData, userData, isSlashCommand) { return client.player.skip(message); // call the skip function from the player } -} +} as Command; diff --git a/commands/music/stop.js b/commands/music/stop.ts similarity index 56% rename from commands/music/stop.js rename to commands/music/stop.ts index 3852175..b3e8d2e 100644 --- a/commands/music/stop.js +++ b/commands/music/stop.ts @@ -1,9 +1,14 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { description: "Stops the music and clears the queue", aliases: ["disconnect", "leave"], - connectedToSameVoiceChannel: true, + commandOptions: { + connectedToSameVC: true + }, async run(client, message, args, guildData, userData, isSlashCommand) { return client.player.stop(message); } -} +} as Command; diff --git a/commands/music/troll.js b/commands/music/troll.ts similarity index 60% rename from commands/music/troll.js rename to commands/music/troll.ts index 3cba136..da23b64 100644 --- a/commands/music/troll.js +++ b/commands/music/troll.ts @@ -1,16 +1,20 @@ +import { Command } from "../../types/command"; +import { ApplicationCommandOptionType } from "discord.js"; + module.exports = { ignore: true, aliases: ["t"], category: "Music", description: "A wild troll appeared.", - connectedToVoiceChannel: true, + connectedToVC: true, run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error if (!isSlashCommand) message.delete(); - // Low the user using the command + // @ts-expect-error // Log the user using the command cause roteKlaue console.log(`${message.author.username} used the troll command.`); client.player.troll(message); return null; } -} +} as Command; diff --git a/commands/testcommands/ping.js b/commands/testcommands/ping.ts similarity index 62% rename from commands/testcommands/ping.js rename to commands/testcommands/ping.ts index e06a34f..455585f 100644 --- a/commands/testcommands/ping.js +++ b/commands/testcommands/ping.ts @@ -1,6 +1,10 @@ +import { Message } from "discord.js"; +import Client from "../../types/client"; +import { Command } from "../../types/command"; + const { EmbedBuilder, Colors } = require("discord.js"); -const after = (client, message, msg, start, slash = false) => { +const after = (client: Client, message: Message, sentMessage: Message, start: number, slash = false) => { const EndDate = Date.now(); const embed = new EmbedBuilder() .setColor(Colors.Red) @@ -10,9 +14,10 @@ const after = (client, message, msg, start, slash = false) => { .setTimestamp(new Date); if (slash) { + // @ts-expect-error // it does exist, ig... message.followUp({ embeds: [embed] }); } else { - msg.delete(); + sentMessage.delete(); return { embeds: [embed] }; } } @@ -24,13 +29,17 @@ module.exports = { const sendObj = { embeds: [new EmbedBuilder().setColor(Colors.Red).setDescription("Please Wait...")] }; const StartDate = Date.now(); if (isSlashCommand) { + // @ts-expect-error // I do think it exists but I just selected the wrong type bc I want to finish this as soon as possible // FIXME await message.deferReply(); + // @ts-expect-error // same here message.followUp(sendObj).then(msg => { + // @ts-expect-error // FIXME pls, this is pure agony after(client, message, msg, StartDate, true); }); } else { - return message.channel.send(sendObj) + return message.channel!.send(sendObj) + // @ts-expect-error // FIXME pls, this is pure agony .then((msg) => { return after(client, message, msg, StartDate) }); } } -} +} as Command; diff --git a/commands/testcommands/playtest.js b/commands/testcommands/playtest.ts similarity index 98% rename from commands/testcommands/playtest.js rename to commands/testcommands/playtest.ts index 8fbf8db..01292a8 100644 --- a/commands/testcommands/playtest.js +++ b/commands/testcommands/playtest.ts @@ -1,3 +1,5 @@ +import { Command } from "../../types/command"; + module.exports = { description: "Plays a random song from a list", aliases: ["pt"], @@ -6,7 +8,7 @@ module.exports = { const pickedSong = songList[Math.floor(Math.random() * songList.length)]; return require("../music/play.js").run(client, message, [pickedSong], guildData, userData, isSlashCommand); } -} +} as Command; const songList = [ "https://www.youtube.com/watch?v=52Gg9CqhbP8&list=RDMM&index=1", diff --git a/commands/testcommands/testbot.js b/commands/testcommands/testbot.ts similarity index 68% rename from commands/testcommands/testbot.js rename to commands/testcommands/testbot.ts index 89a9972..d70a1a2 100644 --- a/commands/testcommands/testbot.js +++ b/commands/testcommands/testbot.ts @@ -1,12 +1,15 @@ +import { Command } from "../../types/command"; + const { EmbedBuilder, ActionRowBuilder, ButtonBuilder } = require("discord.js"); const fs = require("fs"); - module.exports = { + ignore: true, description: "Command for testing all the bot's features", async run(client, message, args, guildData, userData, isSlashCommand) { + // @ts-expect-error // FIXME pls, I think I selected the wrong type message.deferReply({ ephemeral: true }); return null; } -} +} as Command; diff --git a/commands/testcommands/uptime.js b/commands/testcommands/uptime.ts similarity index 93% rename from commands/testcommands/uptime.js rename to commands/testcommands/uptime.ts index 62d053a..5b82e4f 100644 --- a/commands/testcommands/uptime.js +++ b/commands/testcommands/uptime.ts @@ -1,3 +1,5 @@ +import { Command } from "../../types/command"; + const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { @@ -18,4 +20,4 @@ module.exports = { { name: "**Sekunden:**", value: `${seconds}` }); return { embeds: [uptime] }; } -} +} as Command; diff --git a/config.js b/config.ts similarity index 66% rename from config.js rename to config.ts index b29260a..464394a 100644 --- a/config.js +++ b/config.ts @@ -2,16 +2,18 @@ * Config file for nonsensitive data */ +import Client from "./types/client"; + module.exports.prefix = process.env.PREFIX; module.exports.fetchData = require("./functions/fetchDataFromSave.js"); module.exports.authorsString = ""; const { authors } = require("./package.json"); -authors.forEach((author, index) => { +authors.forEach((author: string, index: number) => { if (index === authors.length - 1) module.exports.authorsString += `and ${author}`; else module.exports.authorsString += `${author}, `; }); module.exports.authorsString = module.exports.authorsString.replace(/, and/, " and"); module.exports.version = require("./package.json")["version"]; -module.exports.embedFooter = (client) => ({ text: `Running as ${client.user.tag} on version ${module.exports.version} of the SUS-Bot by ${module.exports.authorsString}` }); \ No newline at end of file +module.exports.embedFooter = (client: Client) => ({ text: `Running as ${client.user.tag} on version ${module.exports.version} of the SUS-Bot by ${module.exports.authorsString}` }); \ No newline at end of file diff --git a/enums/permissionBitField.js b/enums/permissionBitField.ts similarity index 98% rename from enums/permissionBitField.js rename to enums/permissionBitField.ts index 82d26a1..4306fa5 100644 --- a/enums/permissionBitField.js +++ b/enums/permissionBitField.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { CreateInstantInvite: 1n << 0n, KickMembers: 1n << 1n, BanMembers: 1n << 2n, @@ -40,4 +40,4 @@ module.exports = { SendMessagesInThreads: 1n << 38n, UseEmbeddedActivities: 1n << 39n, ModerateMembers: 1n << 40n, -} +} \ No newline at end of file diff --git a/enums/permissionStrings.js b/enums/permissionStrings.ts similarity index 98% rename from enums/permissionStrings.js rename to enums/permissionStrings.ts index b47bb50..d6460ca 100644 --- a/enums/permissionStrings.js +++ b/enums/permissionStrings.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { CreateInstantInvite: "0x0000000000000001", KickMembers: "0x0000000000000002", BanMembers: "0x0000000000000004", diff --git a/events/discord/guildCreate.js b/events/discord/guildCreate.js deleted file mode 100644 index 4c1841a..0000000 --- a/events/discord/guildCreate.js +++ /dev/null @@ -1,15 +0,0 @@ -const guildModel = require("../../schemas/guild"); - -module.exports = async (client, guild) => { - const sus = await guildModel.findOne({ guildId: guild.id }); - if (sus) return; - - console.info("Creating MongoDB entry for guild " + guild.name); - - global.functions.addGuildDocument(guild.id); - - client.commands.forEach(command => { - if (command.name === "prepare") return; - guild.commands?.create(command).catch(e => e); - }); -} diff --git a/events/discord/guildCreate.ts b/events/discord/guildCreate.ts new file mode 100644 index 0000000..63fa67a --- /dev/null +++ b/events/discord/guildCreate.ts @@ -0,0 +1,20 @@ +// @ts-ignore +import guildModel from "../../schemas/guild.js"; + +import { Guild, ApplicationCommandDataResolvable } from "discord.js"; +import Client from "../../types/client.js"; + +module.exports = async (client: Client, guild: Guild) => { + const sus = await guildModel.findOne({ guildId: guild.id }); + if (sus) return; + + console.info("Creating MongoDB entry for guild " + guild.name); + + // @ts-ignore + global.functions.addGuildDocument(guild.id); + + client.commands.forEach(command => { + if (command.name === "prepare") return; + guild.commands?.create(command as ApplicationCommandDataResolvable).catch(e => e); + }); +} diff --git a/events/discord/guildDelete.js b/events/discord/guildDelete.js deleted file mode 100644 index cdc7da6..0000000 --- a/events/discord/guildDelete.js +++ /dev/null @@ -1,6 +0,0 @@ -const guildModel = require("../../schemas/guild"); - -module.exports = async (client, guild) => { - console.info("Deleting MongoDB entry for guild " + guild.name); - guildModel.findOneAndDelete({ guildId: guild.id }, () => { }); -} diff --git a/events/discord/guildDelete.ts b/events/discord/guildDelete.ts new file mode 100644 index 0000000..de5382e --- /dev/null +++ b/events/discord/guildDelete.ts @@ -0,0 +1,9 @@ +import guildModel from "../../schemas/guild.js"; + +import { Guild, ApplicationCommandDataResolvable } from "discord.js"; +import Client from "../../types/client.js"; + +module.exports = async (client: Client, guild: Guild) => { + console.info("Deleting MongoDB entry for guild " + guild.name); + guildModel.findOneAndDelete({ guildId: guild.id }, () => { }); +} diff --git a/events/discord/guildMemberAdd.js b/events/discord/guildMemberAdd.ts similarity index 55% rename from events/discord/guildMemberAdd.js rename to events/discord/guildMemberAdd.ts index e911631..1ae0baa 100644 --- a/events/discord/guildMemberAdd.js +++ b/events/discord/guildMemberAdd.ts @@ -1,10 +1,14 @@ +import Client from "../../types/client"; +import { GuildMember } from "discord.js"; + const fetchData = require("../../config.js").fetchData; const welcomeMessages = fetchData.get("messages").welcome; -const guilds = require("../../schemas/guild"); +import guilds from "../../schemas/guild"; -module.exports = async (client, member) => { +module.exports = async (client: Client, member: GuildMember) => { const guild = await guilds.findOne({ guildId: member.guild.id }); - if (guild?.channels?.welcome === undefined) return; + if (guild?.channels?.welcome === void 0) return; const channel = client.channels.cache.get(guild.channels.welcome); + // @ts-expect-error // i gotta stop doing this channel.send(global.functions.replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); } diff --git a/events/discord/guildMemberRemove.js b/events/discord/guildMemberRemove.ts similarity index 60% rename from events/discord/guildMemberRemove.js rename to events/discord/guildMemberRemove.ts index c2ea2b6..cb4a8d9 100644 --- a/events/discord/guildMemberRemove.js +++ b/events/discord/guildMemberRemove.ts @@ -1,10 +1,14 @@ +import Client from "../../types/client"; +import { GuildMember } from "discord.js"; + const fetchData = require("../../config.js").fetchData; const goodbyeMessages = fetchData.get("messages").goodbye; -const guilds = require("../../schemas/guild"); +import guilds from "../../schemas/guild"; -module.exports = async (client, member) => { +module.exports = async (client: Client, member: GuildMember) => { const guild = await guilds.findOne({ guildId: member.guild.id }); if (!guild?.channels?.goodbye) return; const channel = client.channels.cache.get(guild?.channels?.goodbye); + // @ts-expect-error // I hate this // FIXME: PLS!!! // i gotta stop doing this channel.send(global.functions.replaceUser(goodbyeMessages[Math.floor(Math.random() * goodbyeMessages.length)], member)); } diff --git a/events/discord/interactionCreate.js b/events/discord/interactionCreate.ts similarity index 60% rename from events/discord/interactionCreate.js rename to events/discord/interactionCreate.ts index 02d4173..dd17767 100644 --- a/events/discord/interactionCreate.js +++ b/events/discord/interactionCreate.ts @@ -1,9 +1,14 @@ -module.exports = async (client, interaction) => { +import { Interaction } from "discord.js"; +import Client from "../../types/client"; + +module.exports = async (client: Client, interaction: Interaction) => { let cmd; let args = []; let isComponent = false; + // @ts-expect-error // "doEs NoT eXiSt"... Fuck u TS, that's y I'm checking if it exists if (interaction.customId) + // @ts-expect-error // same as above interaction.customId = interaction.customId.toLowerCase(); let type; @@ -15,32 +20,45 @@ module.exports = async (client, interaction) => { switch (type) { case "COMMAND": + // @ts-expect-error // there is a fucking switch case where I'm checking for it cmd = client.commands.get("command:" + interaction.commandName); + // @ts-expect-error // same as above args = interaction.options?._hoistedOptions.map(e => e.value); break; case "BUTTON": + // @ts-expect-error // same as above if (interaction.customId.startsWith("command:")) { + // @ts-expect-error // same as above cmd = client.commands.get("command:" + interaction.customId.slice(8)); + // @ts-expect-error // same as above args = interaction.customId.slice(8).split(" "); args.shift(); } else { + // @ts-expect-error // same as above cmd = client.commands.get("button:" + interaction.customId.split(" ")[0]); + // @ts-expect-error // same as above args = interaction.customId.split(" "); args.shift(); } isComponent = true; break; case "SELECT_MENU": + // @ts-expect-error // same as above cmd = client.commands.get("selectMenu:" + interaction.customId); + // @ts-expect-error // same as above args = interaction.customId.split(" "); + // @ts-expect-error // same as above args[0] = interaction.values[0]; isComponent = true; break; default: return; } + // @ts-expect-error // "doEs NoT eXiSt"... Fuck u TS, that's y I'm adding it interaction.channel = client.channels.cache.get(interaction.channelId); + // @ts-expect-error // same as above interaction.author = interaction.user; + // @ts-expect-error // i gotta stop doing this global.functions.executeCommand(cmd, client, interaction, args, true, isComponent); } diff --git a/events/discord/messageCreate.js b/events/discord/messageCreate.ts similarity index 68% rename from events/discord/messageCreate.js rename to events/discord/messageCreate.ts index 2f73ff3..28820cd 100644 --- a/events/discord/messageCreate.js +++ b/events/discord/messageCreate.ts @@ -1,11 +1,16 @@ -const guildModel = require("../../schemas/guild"); +import { Message } from "discord.js"; +import Client from "../../types/client"; -module.exports = async (client, message) => { +import guildModel from "../../schemas/guild"; + +module.exports = async (client: Client, message: Message) => { if (message.author.bot) return; // Ignore bots - const guildData = await getGuildData(message.guild.id); + const guildData = await getGuildData(message.guild!.id); + // @ts-expect-error // i gotta stop doing this if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function + // @ts-expect-error // same as above if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels const prefix = client.config.prefix; // Get the prefix from the .env file @@ -13,17 +18,20 @@ module.exports = async (client, message) => { if (!message.content.startsWith(prefix)) return; // Ignore messages that don't start with the prefix const args = message.content.slice(prefix.length).trim().split(/ +/g); // Get the arguments - const commandString = args.shift().toLowerCase(); // Get the command name + const commandString = args.shift()!.toLowerCase(); // Get the command name const command = client.commands.get("command:" + commandString) || // Get the command from the commands collection client.commands.find(command => command.aliases && command.aliases.includes(commandString)); + // @ts-expect-error // I am God, I can create whatever I want TS! message.followUp = message.reply; + // @ts-expect-error // i gotta stop doing this global.functions.executeCommand(command, client, message, args, false); // Execute the command } -async function getGuildData(guildId) { +async function getGuildData(guildId: string) { let guildData = await guildModel.findOne({ guildId: guildId }); if (!guildData) { + // @ts-expect-error // i gotta stop doing this global.functions.addGuildDocument(guildId); guildData = await guildModel.findOne({ guildId: guildId }); } diff --git a/events/discord/ready.js b/events/discord/ready.js deleted file mode 100644 index 65a379d..0000000 --- a/events/discord/ready.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = (client) => { - client.user.setActivity(`${client.config.prefix}help`); - console.success("Bot is ready!"); -} diff --git a/events/discord/ready.ts b/events/discord/ready.ts new file mode 100644 index 0000000..f15d294 --- /dev/null +++ b/events/discord/ready.ts @@ -0,0 +1,7 @@ +import Client from "../../types/client.js"; + +module.exports = (client: Client) => { + client.user.setActivity(`${client.config.prefix}help`); + // @ts-expect-error // it really does... + console.success("Bot is ready!"); +} diff --git a/events/mongodb/connected.js b/events/mongodb/connected.js deleted file mode 100644 index 827e9ff..0000000 --- a/events/mongodb/connected.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (client) => { - console.success("MongoDB connection is ready!"); -} diff --git a/events/mongodb/connected.ts b/events/mongodb/connected.ts new file mode 100644 index 0000000..2a54b12 --- /dev/null +++ b/events/mongodb/connected.ts @@ -0,0 +1,6 @@ +import { Connection } from "mongoose"; + +module.exports = (client: Connection) => { + // @ts-expect-error // gotta add success to the console type + console.success("MongoDB connection is ready!"); +} diff --git a/events/mongodb/connecting.js b/events/mongodb/connecting.js deleted file mode 100644 index 6d4eac1..0000000 --- a/events/mongodb/connecting.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (client) => { - console.info("Connecting to MongoDB..."); -} diff --git a/events/mongodb/connecting.ts b/events/mongodb/connecting.ts new file mode 100644 index 0000000..279e0db --- /dev/null +++ b/events/mongodb/connecting.ts @@ -0,0 +1,5 @@ +import { Connection } from "mongoose"; + +module.exports = (client: Connection) => { + console.info("Connecting to MongoDB..."); +} diff --git a/events/mongodb/disconnected.js b/events/mongodb/disconnected.js deleted file mode 100644 index acaceb0..0000000 --- a/events/mongodb/disconnected.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (client) => { - console.warn("MongoDB connection destroyed!"); -} diff --git a/events/mongodb/disconnected.ts b/events/mongodb/disconnected.ts new file mode 100644 index 0000000..0a27f4e --- /dev/null +++ b/events/mongodb/disconnected.ts @@ -0,0 +1,5 @@ +import { Connection } from "mongoose"; + +module.exports = (client: Connection) => { + console.warn("MongoDB connection destroyed!"); +} diff --git a/events/mongodb/err.js b/events/mongodb/err.js deleted file mode 100644 index 370754c..0000000 --- a/events/mongodb/err.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (client, err) => { - console.error(err); -} diff --git a/events/mongodb/err.ts b/events/mongodb/err.ts new file mode 100644 index 0000000..db9216d --- /dev/null +++ b/events/mongodb/err.ts @@ -0,0 +1,5 @@ +import { Connection } from "mongoose"; + +module.exports = (client: Connection, err: Error) => { + console.error(err); +} diff --git a/functions/addGuildDocument.js b/functions/addGuildDocument.ts similarity index 67% rename from functions/addGuildDocument.js rename to functions/addGuildDocument.ts index 8208e46..a30546e 100644 --- a/functions/addGuildDocument.js +++ b/functions/addGuildDocument.ts @@ -1,9 +1,9 @@ -const guildModel = require("../schemas/guild"); -const { Types } = require("mongoose"); +import guildModel from "../schemas/guild"; +import { Types } from "mongoose"; -module.exports = (guildId) => { +export default (guildId: string) => { (new guildModel({ - _id: Types.ObjectId(), + _id: new Types.ObjectId(), guildId: guildId, channels: { diff --git a/functions/addUserDocument.js b/functions/addUserDocument.ts similarity index 63% rename from functions/addUserDocument.js rename to functions/addUserDocument.ts index d0ee352..e7db32c 100644 --- a/functions/addUserDocument.js +++ b/functions/addUserDocument.ts @@ -1,7 +1,7 @@ -const userModel = require("../schemas/user"); +import userModel from "../schemas/user"; const { Types } = require("mongoose"); -module.exports = (userId) => { +export default (userId: string) => { (new userModel({ _id: Types.ObjectId(), userId: userId, diff --git a/functions/checkChannelID.js b/functions/checkChannelID.ts similarity index 68% rename from functions/checkChannelID.js rename to functions/checkChannelID.ts index 2fff040..77aa1ba 100644 --- a/functions/checkChannelID.js +++ b/functions/checkChannelID.ts @@ -1,7 +1,9 @@ +import { Guild, Message } from "discord.js"; + const fetchData = require("./fetchDataFromSave.js"); -module.exports = (message, guildData) => { - if (guildData?.channels?.allowed === undefined) return true; +module.exports = (message: Message, guildData: any) => { + if (guildData?.channels?.allowed === void 0) return true; const allowedChannelsIDS = guildData.channels.allowed; if (Array.isArray(allowedChannelsIDS)) { if (allowedChannelsIDS.length === 0) return true; diff --git a/functions/convertTime.js b/functions/convertTime.ts similarity index 77% rename from functions/convertTime.js rename to functions/convertTime.ts index 094ad13..6e17fff 100644 --- a/functions/convertTime.js +++ b/functions/convertTime.ts @@ -1,5 +1,5 @@ -module.exports = (seconds) => { - const timeObj = secondsConverter(seconds, "sec"); +module.exports = (seconds: number) => { + const timeObj = secondsConverter(seconds); let returnString = ""; if (timeObj.days > 0) returnString += `${timeObj.days}d`; @@ -15,14 +15,14 @@ module.exports = (seconds) => { return "0s"; } -function secondsConverter(seconds) { - const timeObj = {}; +function secondsConverter(seconds: number) { + const timeObj: any = {}; timeObj.days = Math.floor(seconds / 86400); seconds -= timeObj.days * 86400; timeObj.hours = Math.floor(seconds / 3600); seconds -= timeObj.hours * 3600; timeObj.minutes = Math.floor(seconds / 60); seconds -= timeObj.minutes * 60; - timeObj.seconds = seconds; + timeObj.seconds = Math.floor(seconds); return timeObj; } \ No newline at end of file diff --git a/functions/counter.js b/functions/counter.js deleted file mode 100644 index e3cc269..0000000 --- a/functions/counter.js +++ /dev/null @@ -1,11 +0,0 @@ -const guilds = require("../schemas/guild"); - -module.exports = (message, guildData) => { - if (guildData?.channels?.counter === undefined) return; - if (!(guildData.channels.counter === message.channel.id)) return false; - const current = guildData.counter.current; - if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) - guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err, data) => { }); - else message.delete().catch(); - return true; -} diff --git a/functions/counter.ts b/functions/counter.ts new file mode 100644 index 0000000..5240d2a --- /dev/null +++ b/functions/counter.ts @@ -0,0 +1,17 @@ +import { Message } from "discord.js"; + +import guilds from "../schemas/guild"; + +module.exports = (message: Message, guildData: any) => { + ; + if (guildData?.channels?.counter === void 0) return; + if (!(guildData.channels.counter === message.channel.id)) return false; + const current = guildData.counter.current; + if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) + guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: any) => { + if (err) console.log(err); + if (!data) return "No data found" + }); + else message.delete().catch(); + return true; +} diff --git a/functions/executeCommand.js b/functions/executeCommand.js deleted file mode 100644 index 4e210ba..0000000 --- a/functions/executeCommand.js +++ /dev/null @@ -1,149 +0,0 @@ -// TODO: Add automated argument checking - -const getGuildData = require("./getGuildData.js"); -const getUserData = require("./getUserData.js"); -const formatCommandReturn = require("./formatCommandReturn.js"); -const sendMessage = require("./sendMessage.js"); - -module.exports = async (command, client, interaction, args, isInteraction, isComponent = false) => { - if (command === undefined) return; - - if (command.default_member_permissions - && !isInteraction - && !interaction.member.permissions.has(command.default_member_permissions)) { - const permissionString = getPermissionsString(command.default_member_permissions); - const moreThanOne = (permissionString.match(/,/g) || []).length; - const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; - return interaction.reply(outputString); - } - - if (command.connectedToSameVoiceChannel) - command.connectedToVoiceChannel = true; - - if (command.connectedToVoiceChannel && !interaction.member.voice?.channel) - return interaction.reply("You need to be in a voice channel to use this command."); - - if (command.connectedToSameVoiceChannel && client.player.getQueue(interaction.guildId)?.voiceChannel !== interaction.member.voice?.channel.id) { - if (client.player.getQueue(interaction.guildId)?.voiceChannel === undefined) - return interaction.reply("I am not in a voice channel."); - return interaction.reply("You need to be in the same voice channel as me to use this command."); - } - - const cooldown = client.commandCooldowns.get(command.name).get(interaction.author.id); - if (cooldown !== undefined) - return interaction.reply("You are on cooldown for this command! Wait another " + - global.functions.convertTime( - Math.round(cooldown - Date.now()) / 1000) - + "."); - - // makes reply unavailable so two replies can't be sent - const reply = interaction.reply; - interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand.js. Use return or message.channel.send() instead!") }; - const deferReply = interaction.deferReply; - interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand.js. Use return null instead!") }; - - try { - if (command.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); - - let guildData; - if (interaction.guild) - guildData = await getGuildData(interaction.guild.id); - - let userData = await getUserData(interaction.author.id); - - let returnValue = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); - - if (returnValue === null) { - interaction.deferReply = deferReply; - if (isInteraction) interaction.deferReply(); - return; - } - - let success = returnValue.success || command.success; - - if (success !== undefined && success !== null) { - let cooldownArray = returnValue.success || command.success || [command.cooldown !== undefined]; - - cooldownArray.forEach(commandObject => { - if (typeof commandObject === "string") - commandObject = client.commands.get(commandObject); - if (commandObject === undefined) return console.error("Could not set cooldown, command not found: " + commandObject); - if (typeof commandObject.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + commandObject.name); - client.commandCooldowns.get(commandObject.name).set(interaction.author.id, Date.now() + commandObject.cooldown * 1000); - setTimeout(() => { - client.commandCooldowns.get(commandObject.name).delete(interaction.author.id); - }, commandObject.cooldown * 1000); - }); - } - - // makes reply available again - interaction.reply = reply; - - if (returnValue.DM !== undefined && returnValue.DM !== null) { - sendMessage(returnValue.DM, command, client, interaction, args, isInteraction, guildData, userData, true); - } - - if (interaction.guildId === null) returnValue.announce = true; - sendMessage(returnValue, command, client, interaction, args, isInteraction, guildData, userData, false); - - const disable = returnValue.disableOriginal || command.disableOriginal; - if (disable && isComponent) { - const originalMessage = await interaction.message; - originalMessage.components.forEach(actionRow => { - actionRow.components.forEach(component => { - component.data.disabled = true; - }); - }); - if (originalMessage.content) originalMessage.content += "\n\nThis message has been \u202B\u202B and is now disabled"; - else originalMessage.content = "This message has been \u202B\u202B and is now disabled"; - originalMessage.edit({ content: originalMessage.content, components: originalMessage.components }).catch(() => { }); - } - } catch (e) { - // makes reply available again - interaction.reply = reply; - if (isInteraction) interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(() => { }); - else interaction.reply("An error occurred while executing this command.").catch(() => { }); - console.error(e); - } -} - -// function that converts default_member_permissions bitfield to a human readable string - -function getPermissionsString(permissions) { - if (permissions === 0) return "None"; - if (permissions === 8) return "Administrator"; - if (permissions === 2147483647) return "All"; - const perms = []; - if (permissions & 1) perms.push("Create Instant Invite"); - if (permissions & 2) perms.push("Kick Members"); - if (permissions & 4) perms.push("Ban Members"); - if (permissions & 8) perms.push("Administrator"); - if (permissions & 16) perms.push("Manage Channels"); - if (permissions & 32) perms.push("Manage Guild"); - if (permissions & 64) perms.push("Add Reactions"); - if (permissions & 128) perms.push("View Audit Log"); - if (permissions & 256) perms.push("Priority Speaker"); - if (permissions & 512) perms.push("Stream"); - if (permissions & 1024) perms.push("View Channel"); - if (permissions & 2048) perms.push("Send Messages"); - if (permissions & 4096) perms.push("Send TTS Messages"); - if (permissions & 8192) perms.push("Manage Messages"); - if (permissions & 16384) perms.push("Embed Links"); - if (permissions & 32768) perms.push("Attach Files"); - if (permissions & 65536) perms.push("Read Message History"); - if (permissions & 131072) perms.push("Mention Everyone"); - if (permissions & 262144) perms.push("Use External Emojis"); - if (permissions & 524288) perms.push("View Guild Insights"); - if (permissions & 1048576) perms.push("Connect"); - if (permissions & 2097152) perms.push("Speak"); - if (permissions & 4194304) perms.push("Mute Members"); - if (permissions & 8388608) perms.push("Deafen Members"); - if (permissions & 16777216) perms.push("Move Members"); - if (permissions & 33554432) perms.push("Use VAD"); - if (permissions & 67108864) perms.push("Change Nickname"); - if (permissions & 134217728) perms.push("Manage Nicknames"); - if (permissions & 268435456) perms.push("Manage Roles"); - if (permissions & 536870912) perms.push("Manage Webhooks"); - if (permissions & 1073741824) perms.push("Manage Emojis"); - return perms.join(", "); -} \ No newline at end of file diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts new file mode 100644 index 0000000..e0e5928 --- /dev/null +++ b/functions/executeCommand.ts @@ -0,0 +1,206 @@ +import { PermissionResolvable, Message } from "discord.js"; +import { Command, CommandReturnWithoutString } from "../types/command.js"; +import Client from "../types/client.js"; + +// TODO: Add automated argument checking + +import getGuildData from "./getGuildData"; +import getUserData from "./getUserData"; +// @ts-expect-error +import formatCommandReturn from "./formatCommandReturn"; +import sendMessage from "./sendMessage"; + + +module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { + console.debug(`Executing command ${command.name} by ${interaction.author.tag} (${interaction.author.id})`); + + if (command === void 0) return; + + console.debug(`${command.name} by ${interaction.author.tag} (${interaction.author.id}) is not undefined`); + + console.log(interaction.author) + + if (command.default_member_permissions + && !isInteraction + && !interaction!.member!.permissions.has(command!.default_member_permissions as PermissionResolvable)) { + const permissionString = getPermissionsString(command.default_member_permissions); + const moreThanOne = (permissionString.match(/,/g) || []).length; + const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; + return interaction.reply(outputString); + } + + if (command!.commandOptions?.connectedToSameVC) + command!.commandOptions.connectedToVC = true; + + if (command!.commandOptions?.connectedToVC && !interaction!.member!.voice?.channel) + return interaction.reply("You need to be in a voice channel to use this command."); + + if (command!.commandOptions?.connectedToSameVC && client!.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction!.member!.voice?.channel?.id) { + if (client.player.getQueue(interaction.guildId)?.voiceChannel === void 0) + return interaction.reply("I am not in a voice channel."); + return interaction.reply("You need to be in the same voice channel as me to use this command."); + } + + const cooldownReturn = checkCooldown(command, interaction, client); + if (typeof cooldownReturn === "string") return interaction.reply(cooldownReturn); + + // makes reply unavailable so two replies can't be sent + const reply = interaction.reply; + interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand.js. Use return or message.channel.send() instead!") }; + // @ts-expect-error + const deferReply = interaction.deferReply; + // @ts-expect-error + interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand.js. Use return null instead!") }; + + try { + if (command!.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); + + let guildData; + if (interaction.guild) + guildData = await getGuildData(interaction.guild.id); + + let userData = await getUserData(interaction.author.id); + + let returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); + + if (returnValue === null) { + // @ts-expect-error + interaction.deferReply = deferReply; + // @ts-expect-error + if (isInteraction) interaction.deferReply(); + return; + } + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + let success = returnValue.success || command!.commandOptions?.defaultReturn?.success; + + if (success) { + if (returnValue!.setCooldown) + returnValue.setCooldown.push(command); + else + returnValue!.setCooldown = [command]; + } + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + let cooldownArray: Command[] | undefined = returnValue!.setCooldown || command!.commandOptions?.defaultReturn?.setCooldown; + + if (cooldownArray !== void 0) + cooldownArray.forEach(commandObject => { + setCooldown(commandObject, interaction, client); + }); + + // makes reply available again + interaction.reply = reply; + + if (returnValue.DM !== void 0 && returnValue.DM !== null) { + sendMessage(returnValue.DM, command, client, interaction, args, isInteraction, guildData, userData, true); + } + + if (interaction.guildId === null) returnValue.announce = true; + sendMessage(returnValue, command, client, interaction, args, isInteraction, guildData, userData, false); + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + const disable = returnValue.disableOriginal || command!.commandOptions?.defaultReturn?.disableOriginal; + if (disable && isComponent) { + // @ts-expect-error + const originalMessage = await interaction.message; + // @ts-expect-error + originalMessage.components.forEach(actionRow => { + // @ts-expect-error + actionRow.components.forEach(component => { + component.data.disabled = true; + }); + }); + if (originalMessage.content) originalMessage.content += "\n\nThis message has been \u202B\u202B and is now disabled"; + else originalMessage.content = "This message has been \u202B\u202B and is now disabled"; + originalMessage.edit({ content: originalMessage.content, components: originalMessage.components }).catch(() => { }); + } + } catch (e) { + // makes reply available again + interaction.reply = reply; + // @ts-expect-error + if (isInteraction) interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(() => { }); + else interaction.reply("An error occurred while executing this command.").catch(() => { }); + console.error(e); + } +} + +// function that converts default_member_permissions bitfield to a human readable string + +function getPermissionsString(permissionString: string) { + const permissions = parseInt(permissionString); + if (permissions === 0) return "None"; + if (permissions === 8) return "Administrator"; + if (permissions === 2147483647) return "All"; + const perms = []; + if (permissions & 1) perms.push("Create Instant Invite"); + if (permissions & 2) perms.push("Kick Members"); + if (permissions & 4) perms.push("Ban Members"); + if (permissions & 8) perms.push("Administrator"); + if (permissions & 16) perms.push("Manage Channels"); + if (permissions & 32) perms.push("Manage Guild"); + if (permissions & 64) perms.push("Add Reactions"); + if (permissions & 128) perms.push("View Audit Log"); + if (permissions & 256) perms.push("Priority Speaker"); + if (permissions & 512) perms.push("Stream"); + if (permissions & 1024) perms.push("View Channel"); + if (permissions & 2048) perms.push("Send Messages"); + if (permissions & 4096) perms.push("Send TTS Messages"); + if (permissions & 8192) perms.push("Manage Messages"); + if (permissions & 16384) perms.push("Embed Links"); + if (permissions & 32768) perms.push("Attach Files"); + if (permissions & 65536) perms.push("Read Message History"); + if (permissions & 131072) perms.push("Mention Everyone"); + if (permissions & 262144) perms.push("Use External Emojis"); + if (permissions & 524288) perms.push("View Guild Insights"); + if (permissions & 1048576) perms.push("Connect"); + if (permissions & 2097152) perms.push("Speak"); + if (permissions & 4194304) perms.push("Mute Members"); + if (permissions & 8388608) perms.push("Deafen Members"); + if (permissions & 16777216) perms.push("Move Members"); + if (permissions & 33554432) perms.push("Use VAD"); + if (permissions & 67108864) perms.push("Change Nickname"); + if (permissions & 134217728) perms.push("Manage Nicknames"); + if (permissions & 268435456) perms.push("Manage Roles"); + if (permissions & 536870912) perms.push("Manage Webhooks"); + if (permissions & 1073741824) perms.push("Manage Emojis"); + return perms.join(", "); +} + +function setCooldown(commandString: Command | string, interaction: Message, client: Client) { + let command: Command; + if (typeof commandString === "string") { + const getCommand = client.commands.get(commandString); + if (getCommand === void 0) return console.error("Could not set cooldown, command not found: " + commandString); + command = getCommand; + } else + command = commandString; + if (typeof command!.commandOptions?.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + command.name); + if (command.name === void 0) return console.error("Could not set cooldown, command has no name: " + command.name); + client.commandCooldowns.get(command.name)!.set(interaction!.author.id, Date.now() + command!.commandOptions?.cooldown * 1000); + setTimeout(() => { + client.commandCooldowns.get(command.name as string)!.delete(interaction!.author.id); + }, command!.commandOptions?.cooldown * 1000); +} + +function checkCooldown(commandString: Command | string, interaction: Message, client: Client): string | boolean { + let command: Command; + if (typeof commandString === "string") { + const getCommand = client.commands.get(commandString); + if (getCommand === void 0) throw new Error("Could not check cooldown, command not found: " + commandString); + command = getCommand; + } else + command = commandString; + if (typeof command!.commandOptions?.cooldown !== "number") throw new Error("Could not check cooldown, command has no cooldown: " + command.name); + if (command.name === void 0) throw new Error("Could not check cooldown, command has no name: " + command.name); + if (client.commandCooldowns.get(command.name)!.has(interaction!.author.id)) { + let timeLeft = client.commandCooldowns.get(command.name)!.get(interaction!.author.id)! - Date.now(); + timeLeft /= 1000; + if (timeLeft > 0) { + // @ts-expect-error + const timeString = global.functions.convertTime(timeLeft); + return `You are on cooldown for this command, please wait ${timeString}.` + } + } + return false; +} \ No newline at end of file diff --git a/functions/fetchDataFromSave.js b/functions/fetchDataFromSave.ts similarity index 81% rename from functions/fetchDataFromSave.js rename to functions/fetchDataFromSave.ts index 01c5d1d..c314bdd 100644 --- a/functions/fetchDataFromSave.js +++ b/functions/fetchDataFromSave.ts @@ -1,15 +1,13 @@ -const fs = require("fs"); - const data = require("../data.json"); module.exports = { all: () => { return data; }, - get: (key) => { + get: (key: string) => { return data[key]; }, - set: (key, value) => { + set: (key: string, value: any) => { data[key] = value; }, write: () => { diff --git a/functions/formatCommandReturn.js b/functions/formatCommandReturn.ts similarity index 63% rename from functions/formatCommandReturn.js rename to functions/formatCommandReturn.ts index 2f49379..c406c5c 100644 --- a/functions/formatCommandReturn.js +++ b/functions/formatCommandReturn.ts @@ -1,6 +1,8 @@ +import { Command, CommandReturns } from "../types/command"; + const { Message } = require("discord.js"); -module.exports = async (returnValue, command) => { +module.exports = async (returnValue: any, command: Command) => { return await new Promise(async (resolve, reject) => { if (returnValue instanceof Promise) { const timeout = setTimeout(() => { @@ -11,15 +13,15 @@ module.exports = async (returnValue, command) => { } if (( (typeof returnValue === "string" && returnValue !== "") - || returnValue?.embeds !== undefined - || returnValue?.files !== undefined - || returnValue?.components !== undefined - || returnValue?.content !== undefined - || returnValue?.files !== undefined - || returnValue?.attachments !== undefined + || returnValue?.embeds !== void 0 + || returnValue?.files !== void 0 + || returnValue?.components !== void 0 + || returnValue?.content !== void 0 + || returnValue?.files !== void 0 + || returnValue?.attachments !== void 0 ) && !(returnValue instanceof Message)) { if (typeof returnValue === "string") returnValue = { content: returnValue }; - } else if (returnValue?.DM !== undefined) { + } else if (returnValue?.DM !== void 0) { returnValue.DM = module.exports(returnValue.DM, command); } else if (returnValue !== null) reject(`Command "${command.name}" returned nothing.`); resolve(returnValue); diff --git a/functions/getChannelFromMention.js b/functions/getChannelFromMention.ts similarity index 54% rename from functions/getChannelFromMention.js rename to functions/getChannelFromMention.ts index 2818b1c..bc5129d 100644 --- a/functions/getChannelFromMention.js +++ b/functions/getChannelFromMention.ts @@ -1,4 +1,6 @@ -module.exports = (guild, mention) => { +import { Guild } from "discord.js"; + +module.exports = (guild: Guild, mention: string) => { if (!mention) return; return guild.channels.cache.get(mention.substring(2, mention.length - 1)); } diff --git a/functions/getFiles.js b/functions/getFiles.ts similarity index 60% rename from functions/getFiles.js rename to functions/getFiles.ts index ba5839c..0ed903a 100644 --- a/functions/getFiles.js +++ b/functions/getFiles.ts @@ -1,14 +1,17 @@ const fs = require("fs"); -module.exports = getFiles = (dir, exclude = null) => { - const output = {}; - fs.readdirSync(dir).forEach(path => { +const getFiles = (dir: string, exclude = null) => { + const output: any = {}; + fs.readdirSync(dir).forEach((path: string) => { if (fs.lstatSync(dir + "/" + path).isDirectory()) { output[path] = getFiles(dir + "/" + path, exclude); } else { + if (!path.endsWith(".js")) return; const func = require(`.${dir}/${path}`); output[path.replace(".js", "")] = func; } }); return output; } + +module.exports = getFiles; diff --git a/functions/getGuildData.js b/functions/getGuildData.ts similarity index 61% rename from functions/getGuildData.js rename to functions/getGuildData.ts index 67c5163..b70e580 100644 --- a/functions/getGuildData.js +++ b/functions/getGuildData.ts @@ -1,7 +1,7 @@ -const guildModel = require("../schemas/guild"); -const addGuildDocument = require("./addGuildDocument"); +import guildModel from "../schemas/guild"; +import addGuildDocument from "./addGuildDocument"; -module.exports = async (guildId) => { +export default async (guildId: string) => { let guildData = await guildModel.findOne({ guildId: guildId }); if (!guildData) { addGuildDocument(guildId); diff --git a/functions/getUserData.js b/functions/getUserData.ts similarity index 60% rename from functions/getUserData.js rename to functions/getUserData.ts index ca95f9d..1354cff 100644 --- a/functions/getUserData.js +++ b/functions/getUserData.ts @@ -1,7 +1,7 @@ -const userModel = require("../schemas/user"); -const addUserDocument = require("./addUserDocument"); +import userModel from "../schemas/user"; +import addUserDocument from "./addUserDocument"; -module.exports = async (userId) => { +export default async (userId: string) => { let userData = await userModel.findOne({ userId: userId }); if (!userData) { addUserDocument(userId); diff --git a/functions/isValidYoutubeURL.js b/functions/isValidYoutubeURL.js deleted file mode 100644 index 1909dd2..0000000 --- a/functions/isValidYoutubeURL.js +++ /dev/null @@ -1,40 +0,0 @@ -const validQueryDomains = new Set([ - "youtube.com", - "www.youtube.com", - "m.youtube.com", - "music.youtube.com", - "gaming.youtube.com", -]); - -const validPathDomains = /^https?:\/\/(youtu\.be\/|(www\.)?youtube\.com\/(embed|v|shorts)\/)/; -const idRegex = /^[a-zA-Z0-9-_]{11}$/; - -const getURLVideoID = link => { - const parsed = new URL(link.trim()); - let id = parsed.searchParams.get("v"); - if (validPathDomains.test(link.trim()) && !id) { - const paths = parsed.pathname.split("/"); - id = parsed.host === "youtu.be" ? paths[1] : paths[2]; - } else if (parsed.hostname && !validQueryDomains.has(parsed.hostname)) { - throw Error("Not a YouTube domain"); - } - if (id === undefined) { - throw Error(`No video id found: "${link}"`); - } - id = id.substring(0, 11); - if (!exports.validateID(id)) { - throw TypeError(`Video id (${id}) does not match expected ` + - `format (${idRegex.toString()})`); - } - return id; -}; - - -module.exports.validateURL = string => { - try { - getURLVideoID(string); - return true; - } catch (e) { - return false; - } -}; diff --git a/functions/replaceUser.js b/functions/replaceUser.ts similarity index 51% rename from functions/replaceUser.js rename to functions/replaceUser.ts index d351fa5..2e47c0c 100644 --- a/functions/replaceUser.js +++ b/functions/replaceUser.ts @@ -1,3 +1,5 @@ -module.exports = (message, member) => { +import { GuildMember } from "discord.js"; + +module.exports = (message: string, member: GuildMember) => { return message.replace("{user}", "**" + member.user.username + "#" + member.user.discriminator + "**"); } diff --git a/functions/sendMessage.js b/functions/sendMessage.js deleted file mode 100644 index dcec435..0000000 --- a/functions/sendMessage.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = async (messageToSend, command, client, message, args, isInteraction, guildData, userData, isDM) => { - let sentMessage; - - if (messageToSend.announce || isDM) - messageToSend.ephemeral = false; - else - messageToSend.ephemeral = true; - - if (messageToSend.deleteMessage && !isInteraction) message.delete(); - - if (messageToSend.ephemeral && isInteraction) messageToSend.deleteReply = false; // ephemeral messages can't be deleted - - if (messageToSend.disableMentions) messageToSend.allowedMentions = { parse: [] }; - - messageToSend.failIfNotExists = false; - - if (isDM) { - sentMessage = await message.author.send(messageToSend); - } - else - sentMessage = await message.reply(messageToSend); - - if (messageToSend.deleteReply) { - if (messageToSend.deleteReply === true) messageToSend.deleteReply = 5; - setTimeout(() => { - if (isInteraction) message.deleteReply(); - else sentMessage.delete(); - }, messageToSend.deleteReply * 1000); - } - - if (messageToSend.disable) { - if (messageToSend.disable === true) messageToSend.disable = 5; - setTimeout(() => { - messageToSend.components.forEach(actionRow => { - actionRow.components.forEach(component => { - component.setDisabled(true); - }); - }); - if (isInteraction) message.editReply(messageToSend); - else sentMessage.edit(messageToSend); - }, messageToSend.disable * 1000); - } -} \ No newline at end of file diff --git a/functions/sendMessage.ts b/functions/sendMessage.ts new file mode 100644 index 0000000..05c9dc1 --- /dev/null +++ b/functions/sendMessage.ts @@ -0,0 +1,61 @@ +import { Message, Component, ActionRow, ButtonComponent, BaseSelectMenuComponent } from "discord.js"; +import Client from "../types/client"; +import { Command, CommandReturnWithoutString } from "../types/command"; + +export default async (messageToSend: CommandReturnWithoutString, command: Command, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: any /*idfk*/, userData: any /*same here*/, isDM: boolean) => { + let sentMessage: Message; + + if (messageToSend === null) return; + + if (messageToSend.announce || isDM) + // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need + messageToSend.ephemeral = false; + else + // @ts-expect-error // same as above + messageToSend.ephemeral = true; + + if (messageToSend.deleteMessage && !isInteraction) message.delete(); + + // @ts-expect-error // same as above + if (messageToSend.ephemeral && isInteraction) messageToSend.deleteReply = false; // ephemeral messages can't be deleted + + if (messageToSend.disableMentions) messageToSend.allowedMentions = { parse: [] }; + + // @ts-expect-error // same as above + messageToSend.failIfNotExists = false; + + if (isDM) { + // @ts-expect-error // same as above + sentMessage = await message.author.send(messageToSend); + } + else + // @ts-expect-error // same as above + sentMessage = await message.reply(messageToSend); + + if (messageToSend.deleteReply) { + if (messageToSend.deleteReply === true) messageToSend.deleteReply = 5; + setTimeout(() => { + // @ts-expect-error // idk what I did wrong here, but it's not a big deal, I hope + if (isInteraction) message.deleteReply(); + else sentMessage.delete(); + }, messageToSend.deleteReply * 1000); + } + + if (messageToSend.disable) { + if (messageToSend.disable === true) messageToSend.disable = 5; + setTimeout(() => { + messageToSend.components!.forEach((actionRow: any) => { + actionRow.components.forEach((component: Component) => { + if (component instanceof ButtonComponent || component instanceof BaseSelectMenuComponent) { + // @ts-expect-error // I do, in fact, know what I'm doing TS... Idfc if it's read-only or not + component.disabled = true; + } + }); + }); + // @ts-expect-error // I do think it does exist but I just selected the wrong type bc I want to finish this as soon as possible // FIXME + if (isInteraction) message.editReply(messageToSend); + // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need + else sentMessage.edit(messageToSend); + }, messageToSend.disable * 1000); + } +} \ No newline at end of file diff --git a/functions/shuffle.js b/functions/shuffle.ts similarity index 84% rename from functions/shuffle.js rename to functions/shuffle.ts index 561e9b5..a5e5f14 100644 --- a/functions/shuffle.js +++ b/functions/shuffle.ts @@ -1,4 +1,4 @@ -module.exports = (arrayIn) => { +module.exports = (arrayIn: any[]) => { let array = arrayIn; for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); diff --git a/index.js b/index.ts similarity index 71% rename from index.js rename to index.ts index 635ea5c..c57501a 100644 --- a/index.js +++ b/index.ts @@ -1,6 +1,8 @@ //TODO: Add a command to change the prefix //TODO: Add automated testing //TODO: Add the ability to automatically give members with a certain level a role +import { Command } from "./types/command"; +import ModifiedClient from "./types/client"; const { Client, Collection, GatewayIntentBits } = require("discord.js"); const { connect, connection, set } = require("mongoose"); @@ -21,7 +23,7 @@ const client = new Client({ GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.MessageContent ] -}); +}) as ModifiedClient; /* add important stuff to client */ client.player = new Player(client); @@ -32,16 +34,21 @@ client.connection = connection; console.log(`Version: ${client.config.version} by ${client.config.authorsString}`); /* Loading all the functions. */ +// @ts-expect-error global.functions = require("./functions/getFiles")("./functions", "functions.js"); /* Loading all the commands. */ -loadCommands("commands"); -loadCommands("buttons"); -loadCommands("selectMenus"); +[ + "commands", + "buttons", + "selectMenus" +].forEach((name) => loadCommands(name, true)); + +console.log(client.commands) client.commandCooldowns = new Collection(); -client.commands.forEach(command => { - client.commandCooldowns.set(command.name, new Collection()); +client.commands.forEach((command: Command) => { + client.commandCooldowns.set(command.name!, new Collection()); }); const eventToClientMap = { @@ -50,24 +57,28 @@ const eventToClientMap = { }; /* Loading all the events. */ -fs.readdirSync("./events").forEach((dir) => { +fs.readdirSync("./events").forEach((dir: string) => { if (!fs.lstatSync("./events/" + dir).isDirectory()) return console.warn(`The file ./events/${dir} is not a directory.`); + // @ts-expect-error if (!eventToClientMap[dir]) return console.warn(`The event folder ${dir} is not valid!`); console.log(`Loading ${dir} events...`); - fs.readdirSync(`./events/${dir}`).filter(e => e.endsWith(".js")).forEach(event => { + fs.readdirSync(`./events/${dir}`).filter((e: string) => e.endsWith(".js")).forEach((event: string) => { + // @ts-expect-error eventToClientMap[dir].on(event.split(".")[0], require(`./events/${dir}/${event}`).bind(null, client)); }); }); module.exports = client; +export default client; /* Logging the bot in. */ client.login(process.env.TOKEN); /* Connect to the mongodb database */ connect(process.env.MONGODB); /* Starting the Webserver */ +// @ts-expect-error require("./www/index").startServer(client, process.env.PORT, () => console.success("Webserver ready!")); // makes sure the bot doesn't crash @@ -75,18 +86,18 @@ process.on("uncaughtException", (err) => { console.error(err); }); -function loadCommands(dirName, removeTrailingS = true) { +function loadCommands(dirName: string, removeTrailingS = true) { let dirNameCollection = dirName; if (removeTrailingS) dirNameCollection = dirName.replace(/s$/, ""); - fs.readdirSync(`./${dirName}`).forEach(dir => { + fs.readdirSync(`./${dirName}`).forEach((dir: string) => { if (!fs.lstatSync(`./${dirName}/` + dir).isDirectory()) return console.warn(`./${dirName}/${dir} is not a directory.`); - fs.readdirSync(`./${dirName}/${dir}`).filter(file => file.endsWith(".js")).forEach(file => { + fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".js")).forEach((file: string) => { const command = require(`./${dirName}/${dir}/${file}`); if (command.ignore) return; command.category = `${dirNameCollection}:` + dir; - if (command.name === undefined) command.name = `${dirNameCollection}:` + file.replace(/(\.js)$/, "").toLowerCase(); - else command.name = `${dirNameCollection}:` + command.name.toLowerCase(); + command.name ||= file.replace(/(\.js)$/, ""); + command.name = `${dirNameCollection}:` + command.name.toLowerCase(); client.commands.set(command.name, command); }) }); diff --git a/music/player.js b/music/player.ts similarity index 55% rename from music/player.js rename to music/player.ts index 18f061b..98f964d 100644 --- a/music/player.js +++ b/music/player.ts @@ -1,5 +1,9 @@ -const { createAudioPlayer, createAudioResource, joinVoiceChannel, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); -const { stream: AudioStream, video_basic_info, search, yt_validate } = require("play-dl"); +import { GuildMember, Message, BaseChannel } from "discord.js"; +import { CommandReturnWithoutString } from "../types/command"; + +const { createAudioPlayer, createAudioResource, joinVC, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); +import { stream, video_basic_info, search, yt_validate, YouTubeVideo } from "play-dl"; +import Client from "../types/client"; const { ImprovedArray } = require("sussy-util"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } = require("discord.js"); @@ -40,13 +44,13 @@ module.exports = class Player { #queue = new Map(); #client; - constructor(client) { + constructor(client: Client) { this.#client = client; this.#client.on("voiceStateUpdate", (oldState, newState) => { const queue = this.getQueue(newState.guild.id); - if (queue === undefined || oldState.channelId === null) { + if (queue === void 0 || oldState.channelId === null) { return; } @@ -57,19 +61,18 @@ module.exports = class Player { } return; } - if (newState.channelId === undefined) { + if (newState.channelId === void 0) { queue.current.channel.send("I have been kicked from the channel."); this.#destroyQueue(newState.guild.id); } if (oldState.channelId !== newState.channelId) { queue.voiceChannel = newState.channelId; - client.voiceChannel = newState.channelId; } }); } - #newQueue(guildId) { + #newQueue(guildId: string) { this.#queue.set(guildId, { connection: null, voiceChannel: null, @@ -81,36 +84,38 @@ module.exports = class Player { }); } - #destroyQueue(guildId) { + #destroyQueue(guildId: string) { const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + if (guildInfo === void 0) return; + if (guildInfo.lastNowPlayingMessage !== void 0) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { }); } guildInfo.connection.destroy(); this.#queue.delete(guildId); } - async play(guildId, track) { + async play(guildId: string, track: QueueElement) { const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; + if (guildInfo === void 0) return; guildInfo.current = track; - const stream = await AudioStream(track.url); - const resource = createAudioResource(stream.stream, { inputType: stream.type }); + const streamReturn = await stream(track.url); + const resource = createAudioResource(streamReturn.stream, { inputType: streamReturn.type }); guildInfo.player.play(resource); - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + if (guildInfo.lastNowPlayingMessage !== void 0) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { }); } + // @ts-expect-error guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); } - async #createEmbed(info, type) { + async #createEmbed(info: QueueElement, type: string) { const embed = new EmbedBuilder() .setURL(info.url) .setColor(Colors.Red) .setTimestamp(new Date()) + // @ts-expect-error .setFooter(this.#client.config.embedFooter(this.#client)); if (info.title) { @@ -127,8 +132,8 @@ module.exports = class Player { return embed; } - async addTrack(message, args) { - if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + async addTrack(message: Message, args: string[]) { + if (message.member!.voice?.channel === void 0 || message.member!.voice?.channel === null) return "Connect to a Voice Channel"; let videoName = args.map(e => e.trim()).join(" ").trim(); @@ -152,20 +157,20 @@ module.exports = class Player { } catch (err) { } - if (info === undefined) { - if (this.#queue.get(message.guild.id)?.queue.length === 0) return; - let returnValue = this.skip(message); - returnValue.content = "Can't play tracks requiring age verification! Skipping..."; + if (info === void 0) { + if (this.#queue.get(message.guild!.id)?.queue.length === 0) return; + let returnValue = this.skip(message) as CommandReturnWithoutString; + returnValue!.content = "Can't play tracks requiring age verification! Skipping..."; return returnValue; } - if (!this.#queue.has(message.guild.id)) { - this.#newQueue(message.guild.id); - const queue = this.#queue.get(message.guild.id); - const connection = joinVoiceChannel({ - channelId: message.member.voice.channel.id, - guildId: message.guild.id, - adapterCreator: message.guild.voiceAdapterCreator + if (!this.#queue.has(message.guild!.id)) { + this.#newQueue(message.guild!.id); + const queue = this.#queue.get(message.guild!.id); + const connection = joinVC({ + channelId: message.member!.voice.channel.id, + guildId: message.guild!.id, + adapterCreator: message.guild!.voiceAdapterCreator }); const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); @@ -173,9 +178,8 @@ module.exports = class Player { queue.connection = connection; queue.player = player; - queue.voiceChannel = message.member.voice.channel.id; - this.#client.voiceChannel = message.member.voice.channel.id; - queue.guildId = message.guild.id; + queue.voiceChannel = message.member!.voice.channel.id; + queue.guildId = message.guild!.id; queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { try { @@ -189,120 +193,124 @@ module.exports = class Player { } }); - queue.player.on("error", (err) => { + queue.player.on("error", (err: Error) => { message.channel.send("An error occurred while playing the track."); - this.#destroyQueue(message.guild.id); + this.#destroyQueue(message.guild!.id); }); queue.player.on(AudioPlayerStatus.Idle, () => { if (queue.loop) queue.queue.push(queue.current); const queueElement = queue.queue.shift(); - if (queueElement === undefined) { - this.#destroyQueue(message.guild.id); + if (queueElement === void 0) { + this.#destroyQueue(message.guild!.id); return { content: "Played all tracks leaving the channel.", announce: true }; } - this.play(message.guild.id, queueElement); + this.play(message.guild!.id, queueElement); }); - this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + // @ts-expect-error // I gotta make a type for this + this.play(message.guild!.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); return "Started playing track!"; } - const queue = this.#queue.get(message.guild.id); + const queue = this.#queue.get(message.guild!.id); - if (queue.voiceChannel !== message.member.voice.channel.id) { + if (queue.voiceChannel !== message.member!.voice.channel.id) { return "You have to be in the same voice channel as the bot to add new tracks."; } queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + // @ts-expect-error // idfk, it's getting ignored anyway return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); } - skip(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; + skip(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to skip tracks."; const queueElement = queue.queue.shift(); - if (queueElement === undefined && !queue.loop) { + if (queueElement === void 0 && !queue.loop) { if (queue.loop) { - this.play(message.guild.id, queueElement || queue.current); + this.play(message.guild!.id, queueElement || queue.current); } else { - this.#destroyQueue(message.guild.id); + this.#destroyQueue(message.guild!.id); } return { content: "Skipped last track. Leaving channel!", announce: true }; } else { - this.play(message.guild.id, queueElement || queue.current); + this.play(message.guild!.id, queueElement || queue.current); return { content: "Skipped track.", announce: true }; } } - stop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; + stop(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to stop the bot."; - this.#destroyQueue(message.guild.id); + this.#destroyQueue(message.guild!.id); return { content: "Leaving channel.", announce: true }; } - shuffle(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; + shuffle(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to shuffle the queue."; queue.queue.shuffle(); return { content: "Shuffled the Queue.", announce: true }; } - getQueue(guildId) { + getQueue(guildId: string) { return this.#queue.get(guildId); } - getCurrent(guildId) { + getCurrent(guildId: string) { return this.#queue.get(guildId)?.current; } - clearQueue(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; + clearQueue(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0 || queue.queue.length == 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to clear the queue."; queue.queue.clear(); return { content: "Cleared queue.", announce: true }; } - #channelEmpty(channelId) { - return this.#client.channels.cache.get(channelId)?.members.filter((member) => !member.user.bot).size === 0; + #channelEmpty(channelId: string) { + // @ts-expect-error // I gotta make this compatible with DM Channels + return this.#client.channels.cache.get(channelId)?.members.filter((member: GuildMember) => !member.user.bot).size === 0; } - troll(message) { - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return; + troll(message: Message) { + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return; queue.queue.clear(); /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ - this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); + // @ts-expect-error // I gotta make a type for this + this.play(message.guild!.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); } - toggleLoop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; + toggleLoop(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to toggle looping."; queue.loop = !queue.loop; @@ -313,12 +321,12 @@ module.exports = class Player { } } - pause(message) { - if (message.member.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "There is nothing playing"; + pause(message: Message) { + if (message.member!.voice?.channel === void 0) return "You have to be in the same voice channel as the bot to pause the track"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "There is nothing playing"; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to pause the track"; if (queue.player.state.status == "playing") { @@ -329,12 +337,12 @@ module.exports = class Player { } } - resume(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; + resume(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member.voice.channel.id) + if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to pause"; if (queue.player.state.status == "paused") { @@ -346,7 +354,7 @@ module.exports = class Player { } }; -async function isAgeRestricted(url) { +async function isAgeRestricted(url: string) { try { (await video_basic_info(url)).video_details; } catch (err) { @@ -354,3 +362,17 @@ async function isAgeRestricted(url) { } return false; } + +//queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + +// @ts-expect-error // Idfc +const ytVideo = new YouTubeVideo(); +type thumbnailsType = typeof ytVideo.thumbnails; + +type QueueElement = { + url: string; + channel: BaseChannel; + title: string; + duration?: string; + thumbnails: thumbnailsType; +}; \ No newline at end of file diff --git a/schemas/guild.js b/schemas/guild.ts similarity index 89% rename from schemas/guild.js rename to schemas/guild.ts index 34a37b4..4b42108 100644 --- a/schemas/guild.js +++ b/schemas/guild.ts @@ -28,4 +28,4 @@ const guildSchema = new Schema({ ] }); -module.exports = model("guild", guildSchema, "guilds"); +export default model("guild", guildSchema, "guilds"); diff --git a/schemas/user.js b/schemas/user.ts similarity index 88% rename from schemas/user.js rename to schemas/user.ts index 486ea9b..09335c5 100644 --- a/schemas/user.js +++ b/schemas/user.ts @@ -17,4 +17,5 @@ const userSchema = new Schema({ id: { type: Number, default: 1 }, } }); -module.exports = model("user", userSchema, "users"); + +export default model("user", userSchema, "users"); diff --git a/selectMenus/general/help.js b/selectMenus/general/help.js deleted file mode 100644 index 2cfb932..0000000 --- a/selectMenus/general/help.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - run(client, interaction, args, guildData, userData) { - console.info("helpmenu.js", args); - } -} \ No newline at end of file diff --git a/selectMenus/general/help.ts b/selectMenus/general/help.ts new file mode 100644 index 0000000..2aa9d27 --- /dev/null +++ b/selectMenus/general/help.ts @@ -0,0 +1,8 @@ +import { Component } from "../../types/command"; + +module.exports = { + run(client, interaction, args, guildData, userData) { + console.info("helpmenu.js", args); + return "This command is currently WIP but I already known that you selected " + args[0] + "! MAGIC!"; + } +} as Component; \ No newline at end of file diff --git a/types/client.ts b/types/client.ts new file mode 100644 index 0000000..5dbd45e --- /dev/null +++ b/types/client.ts @@ -0,0 +1,24 @@ +import { Client as DiscordClient, Collection } from "discord.js"; +import { Command } from "./command.js"; +// @ts-ignore: Unreachable code error +import Player from "../music/player"; +import { connection } from "mongoose"; + +export default interface Client extends DiscordClient { + commands: Collection; + player: Player; + commandCooldowns: Collection>; + config: ClientConfig; + functions?: Function[]; + connection: typeof connection; +} + +type ClientConfig = { + token: string; + prefix: string; + authors: string[]; + mongoURI: string; + authorsString: string; + version: string; + embedFooter: { text: string }; +} diff --git a/types/command.ts b/types/command.ts new file mode 100644 index 0000000..342502d --- /dev/null +++ b/types/command.ts @@ -0,0 +1,64 @@ +import { CommandInteraction, ApplicationCommandOption, CacheType, Message, InteractionReplyOptions, MessageReplyOptions } from "discord.js"; +import Client from "./client.js"; + +export interface Command { + ignore?: boolean; + name?: string; + aliases?: string[]; + description: string; + options?: ApplicationCommandOption[]; + default_member_permissions?: string; + commandOptions?: CommandOptions; + category?: string; + run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: any, userData: any, isInteraction: boolean) => CommandReturns; +} + +interface CommandOptions { + connectedToVC?: boolean; + connectedToSameVC?: boolean; + guildOnly?: boolean; + defaultReturn?: CommandReturn; + cooldown?: number; +} + + +interface extensionWithoutDM { + announce?: boolean; + success?: boolean; + setCooldown?: Command[]; + disableOriginal?: boolean; + deleteMessage?: boolean | number; + deleteReply?: boolean | number; + disable?: number | boolean; + disableMentions?: boolean; + timeout?: number; +} + + +interface MessageExtensionsWithoutDMMessage extends MessageReplyOptions, extensionWithoutDM { } + +interface MessageExtensionsMessage extends MessageExtensionsWithoutDMMessage { + DM?: MessageExtensionsWithoutDMMessage; +} + + +interface MessageExtensionsWithoutDMInteraction extends InteractionReplyOptions, extensionWithoutDM { } + +interface MessageExtensionsInteraction extends MessageExtensionsWithoutDMInteraction { + DM?: MessageExtensionsWithoutDMInteraction; +} + + +type MessageExtensions = MessageExtensionsMessage | MessageExtensionsInteraction; + +export type CommandReturn = MessageExtensions | string | null; + +export type CommandReturnWithoutString = MessageExtensions | null; + +export type AsyncCommandReturn = Promise; + +export type CommandReturns = CommandReturn | AsyncCommandReturn; + +// type Overwrite = Pick> & U; + +export type Component = Omit; \ No newline at end of file diff --git a/www/index.js b/www/index.ts similarity index 78% rename from www/index.js rename to www/index.ts index 2cbcb28..467aeb8 100644 --- a/www/index.js +++ b/www/index.ts @@ -1,3 +1,5 @@ +import Client from "../types/client"; + const express = require("express"); const fs = require("fs"); @@ -13,7 +15,7 @@ for (const file of files) { } module.exports = { - startServer: (_client, port, callback) => { + startServer: (client: Client, port: number, callback: Function) => { app.listen(port, callback); } } \ No newline at end of file diff --git a/www/routes/commands.js b/www/routes/commands.ts similarity index 51% rename from www/routes/commands.js rename to www/routes/commands.ts index d8c2dc7..a238851 100644 --- a/www/routes/commands.js +++ b/www/routes/commands.ts @@ -1,23 +1,25 @@ -const { deepClone, removeProperty } = require("sussy-util"); -const permissions = require("../../enums/permissionStrings"); -const client = require("../../index"); -const express = require("express"); +import { deepClone, removeProperty } from "sussy-util"; +import permissions from "../../enums/permissionStrings"; +import client from "../../index"; +// @ts-expect-error +import express from "express"; const router = express.Router(); -router.get("/allcommands", (req, res) => { - const commandName = []; - client.commands.forEach(command => commandName.push({ name: command.name, description: command.description })); +router.get("/allcommands", (req: any, res: any) => { + const commandName = [] as { name: string, description: string }[]; + client.commands.forEach(command => commandName.push({ name: command.name!, description: command.description })); res.send(JSON.stringify(commandName)); }); -router.get("/:cmdname", (req, res) => { +router.get("/:cmdname", (req: any, res: any) => { const cmd = req.params.cmdname; const command = client.commands.find(cmd1 => cmd1.name === cmd); if (!command) return res.status(404).send(""); - const clone = deepClone(command); - clone.permissions?.forEach((e, i) => { + const clone = deepClone(command) as any; + clone.permissions?.forEach((e: any, i: number) => { for (const key in permissions) { + // @ts-expect-error if (BigInt(permissions[key]) != e) continue; clone.permissions[i] = key; diff --git a/www/routes/logo.js b/www/routes/logo.ts similarity index 90% rename from www/routes/logo.js rename to www/routes/logo.ts index b4f1c57..bf7a66a 100644 --- a/www/routes/logo.js +++ b/www/routes/logo.ts @@ -4,7 +4,7 @@ const path = require("path"); const router = express.Router(); -router.get("/", async (req, res) => { +router.get("/", async (req: any, res: any) => { const image = await loadImage(path.resolve(__dirname, "../assets/SUS-Bot-logos_white.png")); const canvas = createCanvas(image.width, image.height); const ctx = canvas.getContext("2d"); diff --git a/www/static/commands/index.js b/www/static/commands/index.ts similarity index 83% rename from www/static/commands/index.js rename to www/static/commands/index.ts index 72df2d5..daf70a6 100644 --- a/www/static/commands/index.js +++ b/www/static/commands/index.ts @@ -1,8 +1,10 @@ +// @ts-expect-error axios.get('../logo').then(e => document.querySelector("#logo").src = e.data).catch(e => console.log(e)); +// @ts-expect-error axios.get(`${window.location.href}/allcommands`).then(e => { const commands = e.data; const content = document.querySelector(".content"); - commands.forEach(cmd => { + commands.forEach((cmd: any) => { const command = document.createElement("a"); command.setAttribute("id", cmd.name); command.href = `${window.location.href}/` + cmd.name; @@ -17,7 +19,7 @@ axios.get(`${window.location.href}/allcommands`).then(e => { command.appendChild(descriptionSpan); const line = document.createElement("span"); line.classList.add("line"); - content.appendChild(command); - content.appendChild(line); + content!.appendChild(command); + content!.appendChild(line); }); -}).catch(e => console.log(e)); \ No newline at end of file +}).catch((e: Error) => console.log(e)); \ No newline at end of file From e182a9e57217758424a93317a2ceb6e4c6d72d63 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:41:35 +0100 Subject: [PATCH 09/28] added js bc this is TS now, baby! --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7d46057..9af988f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ node_modules package-lock.json .vscode logs/* -!**/.gitkeep \ No newline at end of file +!**/.gitkeep +*.js \ No newline at end of file From 681e15cd46f61b7a5a539217ad08d08727ca22f8 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Sun, 15 Jan 2023 23:52:41 +0100 Subject: [PATCH 10/28] fixed some breaking bugs --- events/discord/interactionCreate.ts | 11 ++++++----- functions/executeCommand.ts | 9 +++------ music/player.ts | 8 +------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/events/discord/interactionCreate.ts b/events/discord/interactionCreate.ts index dd17767..9276185 100644 --- a/events/discord/interactionCreate.ts +++ b/events/discord/interactionCreate.ts @@ -54,11 +54,12 @@ module.exports = async (client: Client, interaction: Interaction) => { default: return; } - // @ts-expect-error // "doEs NoT eXiSt"... Fuck u TS, that's y I'm adding it - interaction.channel = client.channels.cache.get(interaction.channelId); - // @ts-expect-error // same as above - interaction.author = interaction.user; + + const modifiedInteraction = interaction as any; + // console.log(typeof modifiedInteraction) + // modifiedInteraction.channel = client.channels.cache.get(modifiedInteraction.channelId); + // modifiedInteraction.author = modifiedInteraction.user; // @ts-expect-error // i gotta stop doing this - global.functions.executeCommand(cmd, client, interaction, args, true, isComponent); + global.functions.executeCommand(cmd, client, modifiedInteraction, args, true, isComponent); } diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index e0e5928..ae68889 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -12,13 +12,11 @@ import sendMessage from "./sendMessage"; module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { - console.debug(`Executing command ${command.name} by ${interaction.author.tag} (${interaction.author.id})`); - + console.log(interaction) if (command === void 0) return; - console.debug(`${command.name} by ${interaction.author.tag} (${interaction.author.id}) is not undefined`); - - console.log(interaction.author) + // @ts-expect-error + interaction.author ||= interaction.message.author; if (command.default_member_permissions && !isInteraction @@ -191,7 +189,6 @@ function checkCooldown(commandString: Command | string, interaction: Message, cl command = getCommand; } else command = commandString; - if (typeof command!.commandOptions?.cooldown !== "number") throw new Error("Could not check cooldown, command has no cooldown: " + command.name); if (command.name === void 0) throw new Error("Could not check cooldown, command has no name: " + command.name); if (client.commandCooldowns.get(command.name)!.has(interaction!.author.id)) { let timeLeft = client.commandCooldowns.get(command.name)!.get(interaction!.author.id)! - Date.now(); diff --git a/music/player.ts b/music/player.ts index 98f964d..527a05e 100644 --- a/music/player.ts +++ b/music/player.ts @@ -363,16 +363,10 @@ async function isAgeRestricted(url: string) { return false; } -//queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - -// @ts-expect-error // Idfc -const ytVideo = new YouTubeVideo(); -type thumbnailsType = typeof ytVideo.thumbnails; - type QueueElement = { url: string; channel: BaseChannel; title: string; duration?: string; - thumbnails: thumbnailsType; + thumbnails: any[]; }; \ No newline at end of file From d1147f58c2d9c85cf4f8b4e738ec5d4aff33100d Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Sun, 29 Jan 2023 22:31:33 +0100 Subject: [PATCH 11/28] fixed some warnings, thx clippy for vs code --- music/player.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/music/player.ts b/music/player.ts index 527a05e..d5617bd 100644 --- a/music/player.ts +++ b/music/player.ts @@ -2,10 +2,10 @@ import { GuildMember, Message, BaseChannel } from "discord.js"; import { CommandReturnWithoutString } from "../types/command"; const { createAudioPlayer, createAudioResource, joinVC, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); -import { stream, video_basic_info, search, yt_validate, YouTubeVideo } from "play-dl"; +import { stream, video_basic_info, search, yt_validate } from "play-dl"; import Client from "../types/client"; -const { ImprovedArray } = require("sussy-util"); -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } = require("discord.js"); +import { ImprovedArray } from "sussy-util"; +import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } from "discord.js"; const playerControls = new ActionRowBuilder() .addComponents( @@ -36,7 +36,7 @@ module.exports = class Player { //TODO: Add previous function --> Completely rewrite the queue system //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) //TODO: Add Spotify support - //TODO: Add Soundcloud support + //TODO: Add SoundCloud support //TODO: Don't get sued by YouTube //TODO: Complete rewrite of the player //BUG: See issue #17 @@ -88,7 +88,7 @@ module.exports = class Player { const guildInfo = this.#queue.get(guildId); if (guildInfo === void 0) return; if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { }); + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); } guildInfo.connection.destroy(); this.#queue.delete(guildId); @@ -104,7 +104,7 @@ module.exports = class Player { guildInfo.player.play(resource); if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { }); + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); } // @ts-expect-error guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); @@ -196,6 +196,7 @@ module.exports = class Player { queue.player.on("error", (err: Error) => { message.channel.send("An error occurred while playing the track."); this.#destroyQueue(message.guild!.id); + err; }); queue.player.on(AudioPlayerStatus.Idle, () => { From ca556f92a87090d24278dbef7e72ee5336421eb3 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:12:14 +0100 Subject: [PATCH 12/28] Sorry for the long commit but I changed a ton and fixed a lot of warnings --- .eslintrc.js | 56 ++++ .gitignore | 3 +- buttons/economy/resetBalance.ts | 6 +- buttons/economy/resetLevel.ts | 4 +- buttons/economy/search.ts | 10 +- buttons/general/support.ts | 4 +- commands/economy/balance.ts | 3 +- commands/economy/beg.ts | 83 +++-- commands/economy/bet.ts | 10 +- commands/economy/deposit.ts | 2 +- commands/economy/level.ts | 3 +- commands/economy/resetBalance.ts | 3 +- commands/economy/resetLevel.ts | 3 +- commands/economy/search.ts | 3 +- commands/economy/withdraw.ts | 2 +- commands/economy/work.ts | 2 +- commands/games/coinflip.ts | 2 +- commands/games/numberguess.ts | 2 +- commands/general/help.ts | 4 +- commands/general/info.ts | 2 +- commands/general/invite.ts | 3 +- commands/general/inviteBot.ts | 2 +- commands/general/serverinfo.ts | 3 +- commands/general/userinfo.ts | 3 +- commands/moderation/clear.ts | 2 +- commands/moderation/lock.ts | 2 +- commands/moderation/nickname.ts | 2 +- commands/moderation/prepare.ts | 6 +- commands/moderation/remove-nickname.ts | 3 +- commands/moderation/set-counter-channel.ts | 2 +- commands/moderation/set-goodbye-channel.ts | 2 +- commands/moderation/set-welcome-channel.ts | 2 +- commands/moderation/slowmode.ts | 3 +- commands/moderation/unban.ts | 2 +- commands/moderation/unlock.ts | 2 +- commands/music/clearQueue.ts | 3 +- commands/music/loop.ts | 3 +- commands/music/nowPlaying.ts | 3 +- commands/music/pause.ts | 3 +- commands/music/play.ts | 2 +- commands/music/queue.ts | 3 +- commands/music/resume.ts | 3 +- commands/music/shuffle.ts | 3 +- commands/music/skip.ts | 3 +- commands/music/stop.ts | 3 +- commands/music/troll.ts | 3 +- commands/testcommands/ping.ts | 4 +- commands/testcommands/playtest.ts | 4 +- commands/testcommands/testbot.ts | 5 +- commands/testcommands/uptime.ts | 2 +- config.ts | 2 +- events/discord/guildCreate.ts | 4 +- events/discord/guildDelete.ts | 4 +- events/discord/guildMemberAdd.ts | 2 +- events/discord/guildMemberRemove.ts | 2 +- events/discord/ready.ts | 2 +- functions/checkChannelID.ts | 2 +- functions/counter.ts | 3 +- functions/executeCommand.ts | 9 +- functions/fetchDataFromSave.ts | 1 + functions/getFiles.ts | 4 +- index.ts | 10 +- music/player.js | 356 +++++++++++++++++++++ music/{player.ts => player.ts.ignore} | 0 package.json | 5 +- tsconfig.json | 2 +- tslint-to-eslint-config.log | 4 + tslint.json | 13 + types/client.ts | 2 +- types/command.ts | 2 +- 70 files changed, 563 insertions(+), 159 deletions(-) create mode 100644 .eslintrc.js create mode 100644 music/player.js rename music/{player.ts => player.ts.ignore} (100%) create mode 100644 tslint-to-eslint-config.log create mode 100644 tslint.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..5f0fc75 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,56 @@ +/* +👋 Hi! This file was autogenerated by tslint-to-eslint-config. +https://github.com/typescript-eslint/tslint-to-eslint-config + +It represents the closest reasonable ESLint configuration to this +project's original TSLint configuration. + +We recommend eventually switching this configuration to extend from +the recommended rulesets in typescript-eslint. +https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md + +Happy linting! 💖 +*/ +module.exports = { + "env": { + "browser": true, + "es6": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "root": true, + "rules": { + "@typescript-eslint/member-delimiter-style": [ + "warn", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/naming-convention": "warn", + "@typescript-eslint/no-unused-expressions": "warn", + "@typescript-eslint/semi": [ + "warn", + "always" + ], + "eqeqeq": [ + "warn", + "always" + ], + "no-redeclare": "warn", + "no-unused-expressions": "off", + "semi": "off" + } +}; diff --git a/.gitignore b/.gitignore index 9af988f..7d46057 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,4 @@ node_modules package-lock.json .vscode logs/* -!**/.gitkeep -*.js \ No newline at end of file +!**/.gitkeep \ No newline at end of file diff --git a/buttons/economy/resetBalance.ts b/buttons/economy/resetBalance.ts index 460bc39..c1c01d9 100644 --- a/buttons/economy/resetBalance.ts +++ b/buttons/economy/resetBalance.ts @@ -1,12 +1,12 @@ import { Component } from "../../types/command"; -const userList = require("../../schemas/user"); +import userList from "../../schemas/user"; module.exports = { - run(client, interaction, args, guildData, userData) { + run(_client, _interaction, _args, _guildData, userData) { userData.economy.wallet = 0; userData.economy.bank = 0; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { err; data; }); return { content: "Your balance has been reset!", disableOriginal: true }; } } as Component; \ No newline at end of file diff --git a/buttons/economy/resetLevel.ts b/buttons/economy/resetLevel.ts index cc55919..b4f2aae 100644 --- a/buttons/economy/resetLevel.ts +++ b/buttons/economy/resetLevel.ts @@ -3,9 +3,9 @@ import { Component } from "../../types/command"; const userList = require("../../schemas/user"); module.exports = { - run(client, interaction, args, guildData, userData) { + run(_client, _interaction, _args, _guildData, userData) { userData.level.xp = 0; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); return { content: "Your level has been reset!", disableOriginal: true }; } } as Component; \ No newline at end of file diff --git a/buttons/economy/search.ts b/buttons/economy/search.ts index 9eb7350..cb8d1d6 100644 --- a/buttons/economy/search.ts +++ b/buttons/economy/search.ts @@ -1,20 +1,20 @@ import { Component } from "../../types/command"; -const userList = require("../../schemas/user.js"); -const { Random } = require("sussy-util"); +import userList from "../../schemas/user"; +import { Random } from "sussy-util"; module.exports = { name: "search", commandOptions: { cooldown: 60 }, - async run(client, interaction, args, guildData, userData) { + async run(_client, _interaction, args, _guildData, userData) { const amount = Random.randomInt(900, 1600); const current = userData.economy; current.wallet += amount; - userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { }); + userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { err; data; }); userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; } } as Component; \ No newline at end of file diff --git a/buttons/general/support.ts b/buttons/general/support.ts index e38b4f8..4af702b 100644 --- a/buttons/general/support.ts +++ b/buttons/general/support.ts @@ -1,9 +1,9 @@ import { Component } from "../../types/command"; -const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"); +import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; module.exports = { - run(client, interaction) { + run(_client, _interaction) { const choice = new ActionRowBuilder() .addComponents( new ButtonBuilder() diff --git a/commands/economy/balance.ts b/commands/economy/balance.ts index bc7c070..c6ae1eb 100644 --- a/commands/economy/balance.ts +++ b/commands/economy/balance.ts @@ -1,11 +1,10 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Shows the balance of your money", aliases: ["bal"], - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, _message, _args, _guildData, userData, _isSlashCommand) { return "You have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; } diff --git a/commands/economy/beg.ts b/commands/economy/beg.ts index 297905e..c4fd65a 100644 --- a/commands/economy/beg.ts +++ b/commands/economy/beg.ts @@ -1,48 +1,47 @@ -import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; +// import { Command } from "../../types/command"; -const userList = require("../../schemas/user"); -const messages = require("../../resources/messages.json"); +// import userList from "../../schemas/user"; +// import messages from "../../resources/messages.json"; -module.exports = { - ignore: true, // the messages is kinda broken - //TODO: fix the messages +// module.exports = { +// ignore: true, // the messages is kinda broken +// //TODO: fix the messages - description: "Beg to earn money", - cooldown: 60, +// description: "Beg to earn money", +// cooldown: 60, - run(client, message, args, guildData, userData, isSlashCommand) { - if (userData.economy?.wallet < 200) - return "Not enough money to risk on losing"; - const earned = Math.round(Math.random() * 400) - 200; - userData.economy.wallet += earned; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { - message.channel!.send(`<@${userData.userId}>` + " just levelled up!") - } +// run(_client, message, _args, _guildData, userData, _isSlashCommand) { +// if (userData.economy?.wallet < 200) +// return "Not enough money to risk on losing"; +// const earned = Math.round(Math.random() * 400) - 200; +// userData.economy.wallet += earned; +// userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { +// if (err) console.error(err); +// if (!data) return "Error: User not found."; +// }); +// userData.level.xp += 2; +// userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { +// if (err) console.error(err); +// if (!data) return "Error: User not found."; +// }); +// if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { +// message.channel!.send(`<@${userData.userId}>` + " just levelled up!") +// } - let valueRange = Math.ceil(Math.abs(earned / 100)); - if (earned < 0) valueRange *= -1; +// let valueRange = Math.ceil(Math.abs(earned / 100)); +// if (earned < 0) valueRange *= -1; - switch (valueRange) { - case -2: - return messages.beg.veryBad.replace("{amount}", Math.abs(earned)); - case -1: - return messages.beg.bad.replace("{amount}", Math.abs(earned)); - case 0: - return messages.beg.neutral; - case 1: - return messages.beg.good.replace("{amount}", earned); - case 2: - return messages.beg.veryGood.replace("{amount}", earned); - } - } -} as Command; \ No newline at end of file +// switch (valueRange) { +// case -2: +// return messages.beg.veryBad.replace("{amount}", Math.abs(earned)); +// case -1: +// return messages.beg.bad.replace("{amount}", Math.abs(earned)); +// case 0: +// return messages.beg.neutral; +// case 1: +// return messages.beg.good.replace("{amount}", earned); +// case 2: +// return messages.beg.veryGood.replace("{amount}", earned); +// } +// } +// } as Command; \ No newline at end of file diff --git a/commands/economy/bet.ts b/commands/economy/bet.ts index 38d0b68..cf779dc 100644 --- a/commands/economy/bet.ts +++ b/commands/economy/bet.ts @@ -1,15 +1,13 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; -const userList = require("../../schemas/user"); -const { EmbedBuilder } = require("discord.js"); -const jobs = require("./resources/jobs.json").jobs; -const { IsSomething } = require("sussy-util"); +import userList from "../../schemas/user"; +import { EmbedBuilder } from "discord.js"; +import { IsSomething } from "sussy-util"; module.exports = { description: "Bet your money and win!", - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, _message, args, _guildData, userData, _isSlashCommand) { const embed = new EmbedBuilder() .setTimestamp(new Date()) diff --git a/commands/economy/deposit.ts b/commands/economy/deposit.ts index 8a69739..9313e5c 100644 --- a/commands/economy/deposit.ts +++ b/commands/economy/deposit.ts @@ -18,7 +18,7 @@ module.exports = { ], - run: (_client, message, args, _guildInfo, userInfo) => { + run: (_client, _message, args, _guildInfo, userInfo) => { if (!args[0]) return "Please provide the amount you want to deposit."; const current = userInfo.economy; diff --git a/commands/economy/level.ts b/commands/economy/level.ts index ba9856f..60adf26 100644 --- a/commands/economy/level.ts +++ b/commands/economy/level.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { IsSomething } = require("sussy-util"); const { EmbedBuilder } = require("discord.js"); @@ -7,7 +6,7 @@ module.exports = { description: "Shows the level of your account", aliases: ["lvl"], - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, _message, _args, _guildData, userData, _isSlashCommand) { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Level panel") diff --git a/commands/economy/resetBalance.ts b/commands/economy/resetBalance.ts index 786f135..de2b84c 100644 --- a/commands/economy/resetBalance.ts +++ b/commands/economy/resetBalance.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); @@ -7,7 +6,7 @@ module.exports = { description: "Clears your balance", aliases: ["clb", "clearbalance", "resetbalance", "rb", "resetbal", "clearbal"], - run(client, message, args, guildData, userData, isInteraction) { + run(client, _message, _args, _guildData, _userData, isInteraction) { const embed = new EmbedBuilder() .setTitle("Reset Balance") .setDescription("Are you sure you want to reset your balance?") diff --git a/commands/economy/resetLevel.ts b/commands/economy/resetLevel.ts index af70dc5..507fe70 100644 --- a/commands/economy/resetLevel.ts +++ b/commands/economy/resetLevel.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); @@ -7,7 +6,7 @@ module.exports = { description: "Clears your level", aliases: ["cll", "clearlevel", "resetlevel", "rl", "resetlvl", "clearlvl"], - run(client, message, args, guildData, userData, isInteraction) { + run(client, _message, _args, _guildData, _userData, isInteraction) { const embed = new EmbedBuilder() .setTitle("Reset Level") .setDescription("Are you sure you want to reset your level?") diff --git a/commands/economy/search.ts b/commands/economy/search.ts index 03097ea..3ff69a8 100644 --- a/commands/economy/search.ts +++ b/commands/economy/search.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { StringUtil } = require("sussy-util"); const { EmbedBuilder, Colors, ActionRowBuilder, StringSelectMenuBuilder, SelectMenuOptionBuilder, ButtonStyle, ButtonBuilder } = require("discord.js"); @@ -11,7 +10,7 @@ module.exports = { cooldown: 60 }, - run: (_client, message, _args, _guildData, userData) => { + run: (_client, _message, _args, _guildData, _userData) => { const places = [ "bank", "river", diff --git a/commands/economy/withdraw.ts b/commands/economy/withdraw.ts index 477da52..e172365 100644 --- a/commands/economy/withdraw.ts +++ b/commands/economy/withdraw.ts @@ -13,7 +13,7 @@ module.exports = { required: true, }], - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, _message, args, _guildData, userData, _isSlashCommand) { let amount = args[0]; if (amount && IsSomething.isNumber(amount)) { if (amount > userData.economy.bank) amount = userData.economy.bank; diff --git a/commands/economy/work.ts b/commands/economy/work.ts index ae9ec91..51c164a 100644 --- a/commands/economy/work.ts +++ b/commands/economy/work.ts @@ -17,7 +17,7 @@ module.exports = { required: true, }], - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, message, _args, _guildData, userData, _isSlashCommand) { if (userData.economy) { let earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); userData.economy.wallet += earned; diff --git a/commands/games/coinflip.ts b/commands/games/coinflip.ts index 3d8e43e..4f6bdde 100644 --- a/commands/games/coinflip.ts +++ b/commands/games/coinflip.ts @@ -11,7 +11,7 @@ module.exports = { required: false, }], - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, message, args, _guildData, _userData, _isSlashCommand) { const coinArray = ["heads", "tails"]; let numberThrow = Math.floor(Math.random() * 2); if (!(args[0] === `heads`) && !(args[0] === 'tails')) { diff --git a/commands/games/numberguess.ts b/commands/games/numberguess.ts index b265baf..1d7f6df 100644 --- a/commands/games/numberguess.ts +++ b/commands/games/numberguess.ts @@ -20,7 +20,7 @@ module.exports = { } ], - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, message, args, _guildData, _userData, _isSlashCommand) { if (args[0] === void 0 || args[0] === `` || args[1] === void 0 || args[1] === ``) { return "Please specify two numbers"; } diff --git a/commands/general/help.ts b/commands/general/help.ts index dbceebb..899b18f 100644 --- a/commands/general/help.ts +++ b/commands/general/help.ts @@ -1,7 +1,7 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, StringSelectMenuBuilder } = require("discord.js"); +const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); const { StringUtil } = require("sussy-util"); const fs = require("fs"); @@ -19,7 +19,7 @@ module.exports = { } ], - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, _message, args, _guildData, _userData, _isSlashCommand) { const menu = new StringSelectMenuBuilder() .setCustomId("help") .setPlaceholder("Select a category"); diff --git a/commands/general/info.ts b/commands/general/info.ts index e81ab4a..40b70c4 100644 --- a/commands/general/info.ts +++ b/commands/general/info.ts @@ -7,7 +7,7 @@ const ms = require("@parade/pretty-ms"); module.exports = { description: "Displays information about the bot.", - run(client, message) { + run(client, _message, _args, _guildData, _userData, _isSlashCommand) { return { embeds: [new EmbedBuilder() .setColor(Colors.Red) diff --git a/commands/general/invite.ts b/commands/general/invite.ts index 658840e..e6105fa 100644 --- a/commands/general/invite.ts +++ b/commands/general/invite.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Sends the invite link of the server", @@ -7,7 +6,7 @@ module.exports = { guildOnly: true, }, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // It can't even get to this point if it's not a guild const invite = await message.channel!.createInvite({ unique: true, temporary: true }); return "https://discord.gg/" + invite.code; diff --git a/commands/general/inviteBot.ts b/commands/general/inviteBot.ts index 81858bb..7d8b441 100644 --- a/commands/general/inviteBot.ts +++ b/commands/general/inviteBot.ts @@ -4,7 +4,7 @@ import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Sends the invite link of the bot", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { return { content: "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands" }; } } as Command; diff --git a/commands/general/serverinfo.ts b/commands/general/serverinfo.ts index 13cf8c4..42d0eef 100644 --- a/commands/general/serverinfo.ts +++ b/commands/general/serverinfo.ts @@ -1,12 +1,11 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { description: "Shows information about the server", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { const sEmbed = new EmbedBuilder() .setColor(Colors.Red) .setTitle("Server Info") diff --git a/commands/general/userinfo.ts b/commands/general/userinfo.ts index f964a51..c754c18 100644 --- a/commands/general/userinfo.ts +++ b/commands/general/userinfo.ts @@ -1,12 +1,11 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { EmbedBuilder, Colors } = require('discord.js'); module.exports = { description: "Displays information about the current user.", - run(client, message, args) { + run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // yes, it does exist! const user = message.mentions!.users.first() || client.users.cache.get(args[0]) || message.author; diff --git a/commands/moderation/clear.ts b/commands/moderation/clear.ts index 31991a8..df80d9e 100644 --- a/commands/moderation/clear.ts +++ b/commands/moderation/clear.ts @@ -17,7 +17,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageMessages, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, _guildData, _userData, isSlashCommand) { const amount = parseInt(args[0]); if (args[0] === "all") { diff --git a/commands/moderation/lock.ts b/commands/moderation/lock.ts index f7cc0f3..3a229f8 100644 --- a/commands/moderation/lock.ts +++ b/commands/moderation/lock.ts @@ -20,7 +20,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; diff --git a/commands/moderation/nickname.ts b/commands/moderation/nickname.ts index c57ed5c..0830d77 100644 --- a/commands/moderation/nickname.ts +++ b/commands/moderation/nickname.ts @@ -24,7 +24,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageNicknames, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); let nickName; diff --git a/commands/moderation/prepare.ts b/commands/moderation/prepare.ts index eab0dc3..f767fa2 100644 --- a/commands/moderation/prepare.ts +++ b/commands/moderation/prepare.ts @@ -1,6 +1,6 @@ import { Command } from "../../types/command"; import Client from "../../types/client"; -import { ApplicationCommandOptionType, CommandInteraction, Message } from "discord.js"; +import { CommandInteraction, Message } from "discord.js"; const { EmbedBuilder } = require("discord.js"); @@ -15,7 +15,7 @@ const registering = (client: Client, message: CommandInteraction | Message client.commands.forEach((command: Command) => { if (command.name === "prepare") return; - // @ts-expect-error // cause name can't be undefined, look at index.js + // @ts-expect-error // cause name can't be undefined, look at index.ts message.guild!.commands?.create(command).catch((error: Error) => { return new EmbedBuilder() .setTitle("Failed to create slash-commands") @@ -29,7 +29,7 @@ const registering = (client: Client, message: CommandInteraction | Message module.exports = { description: "Creates slash commands in server", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { const embed = registering(client, message); return { embeds: [embed] }; } diff --git a/commands/moderation/remove-nickname.ts b/commands/moderation/remove-nickname.ts index 23505bf..1c6e27b 100644 --- a/commands/moderation/remove-nickname.ts +++ b/commands/moderation/remove-nickname.ts @@ -1,7 +1,6 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; -import permissionBitField from "../../enums/permissionBitField"; import permissionStrings from "../../enums/permissionStrings"; module.exports = { @@ -19,7 +18,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageNicknames, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); mentionedMember ||= message.member; diff --git a/commands/moderation/set-counter-channel.ts b/commands/moderation/set-counter-channel.ts index 04f0410..74410d7 100644 --- a/commands/moderation/set-counter-channel.ts +++ b/commands/moderation/set-counter-channel.ts @@ -20,7 +20,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, guildData, _userData, _isSlashCommand) { // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === void 0) channel = message.channel; diff --git a/commands/moderation/set-goodbye-channel.ts b/commands/moderation/set-goodbye-channel.ts index 74209b7..4ace7bf 100644 --- a/commands/moderation/set-goodbye-channel.ts +++ b/commands/moderation/set-goodbye-channel.ts @@ -20,7 +20,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, guildData, _userData, _isSlashCommand) { // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; diff --git a/commands/moderation/set-welcome-channel.ts b/commands/moderation/set-welcome-channel.ts index ddde3c8..44649fe 100644 --- a/commands/moderation/set-welcome-channel.ts +++ b/commands/moderation/set-welcome-channel.ts @@ -20,7 +20,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, guildData, _userData, _isSlashCommand) { // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; diff --git a/commands/moderation/slowmode.ts b/commands/moderation/slowmode.ts index 19eea03..87e81f9 100644 --- a/commands/moderation/slowmode.ts +++ b/commands/moderation/slowmode.ts @@ -1,7 +1,6 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; -const { IsSomething } = require("sussy-util"); import permissionStrings from "../../enums/permissionStrings"; module.exports = { @@ -24,7 +23,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, message, args, _guildData, _userData, _isSlashCommand) { let rate; // @ts-expect-error diff --git a/commands/moderation/unban.ts b/commands/moderation/unban.ts index 202f4ca..67e0ed7 100644 --- a/commands/moderation/unban.ts +++ b/commands/moderation/unban.ts @@ -18,7 +18,7 @@ module.exports = { default_member_permissions: permissionStrings.BanMembers, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { if (args[0] === void 0) return "Please Give Me Member ID That You Want To Unban!"; diff --git a/commands/moderation/unlock.ts b/commands/moderation/unlock.ts index 26cb49e..f5e6f64 100644 --- a/commands/moderation/unlock.ts +++ b/commands/moderation/unlock.ts @@ -20,7 +20,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; diff --git a/commands/music/clearQueue.ts b/commands/music/clearQueue.ts index a045757..38c8348 100644 --- a/commands/music/clearQueue.ts +++ b/commands/music/clearQueue.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Clears the song queue.", @@ -7,7 +6,7 @@ module.exports = { connectedToSameVC: true }, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.clearQueue(message); } } as Command; diff --git a/commands/music/loop.ts b/commands/music/loop.ts index 443fb0e..9a503ca 100644 --- a/commands/music/loop.ts +++ b/commands/music/loop.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Loops the current queue.", @@ -7,7 +6,7 @@ module.exports = { commandOptions: { connectedToSameVC: true }, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.toggleLoop(message); }, } as Command; diff --git a/commands/music/nowPlaying.ts b/commands/music/nowPlaying.ts index 38ee517..1423f82 100644 --- a/commands/music/nowPlaying.ts +++ b/commands/music/nowPlaying.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Shows the current song", @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { if (client.player.getQueue(message.guild!.id) === void 0) { return "There is no queue"; } diff --git a/commands/music/pause.ts b/commands/music/pause.ts index 0ac1939..2820570 100644 --- a/commands/music/pause.ts +++ b/commands/music/pause.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { aliases: [], @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.pause(message); } } as Command; diff --git a/commands/music/play.ts b/commands/music/play.ts index 070284d..d24155a 100644 --- a/commands/music/play.ts +++ b/commands/music/play.ts @@ -15,7 +15,7 @@ module.exports = { } ], - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // cause it's getting caught anyway try { message.suppressEmbeds(true); } catch (e) { } return client.player.addTrack(message, args); diff --git a/commands/music/queue.ts b/commands/music/queue.ts index 60e38ca..00bda23 100644 --- a/commands/music/queue.ts +++ b/commands/music/queue.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Shows the song queue", @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { const playerInfo = client.player.getQueue(message.guild!.id); if (playerInfo === void 0) { diff --git a/commands/music/resume.ts b/commands/music/resume.ts index 3f297fc..10fba2d 100644 --- a/commands/music/resume.ts +++ b/commands/music/resume.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { aliases: ["unpause"], @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.resume(message); } } as Command; diff --git a/commands/music/shuffle.ts b/commands/music/shuffle.ts index 9fedc34..2e273e6 100644 --- a/commands/music/shuffle.ts +++ b/commands/music/shuffle.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Shuffles the queue", @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.shuffle(message); } } as Command; diff --git a/commands/music/skip.ts b/commands/music/skip.ts index c007d2a..cb44f3e 100644 --- a/commands/music/skip.ts +++ b/commands/music/skip.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Skips current track", @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.skip(message); // call the skip function from the player } } as Command; diff --git a/commands/music/stop.ts b/commands/music/stop.ts index b3e8d2e..74cdd78 100644 --- a/commands/music/stop.ts +++ b/commands/music/stop.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Stops the music and clears the queue", @@ -8,7 +7,7 @@ module.exports = { connectedToSameVC: true }, - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.stop(message); } } as Command; diff --git a/commands/music/troll.ts b/commands/music/troll.ts index da23b64..ad7fd78 100644 --- a/commands/music/troll.ts +++ b/commands/music/troll.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { ignore: true, @@ -8,7 +7,7 @@ module.exports = { description: "A wild troll appeared.", connectedToVC: true, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, _args, _guildData, _userData, isSlashCommand) { // @ts-expect-error if (!isSlashCommand) message.delete(); diff --git a/commands/testcommands/ping.ts b/commands/testcommands/ping.ts index 455585f..d32dff6 100644 --- a/commands/testcommands/ping.ts +++ b/commands/testcommands/ping.ts @@ -22,10 +22,12 @@ const after = (client: Client, message: Message, sentMessage: Message, sta } } +//TODO: I implemented returning null for a reason... So ig I should use it here + module.exports = { description: "Pings the bot and displays the latency of the bot and the latency of the api.", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, _guildData, _userData, isSlashCommand) { const sendObj = { embeds: [new EmbedBuilder().setColor(Colors.Red).setDescription("Please Wait...")] }; const StartDate = Date.now(); if (isSlashCommand) { diff --git a/commands/testcommands/playtest.ts b/commands/testcommands/playtest.ts index 01292a8..40026cf 100644 --- a/commands/testcommands/playtest.ts +++ b/commands/testcommands/playtest.ts @@ -4,9 +4,9 @@ module.exports = { description: "Plays a random song from a list", aliases: ["pt"], - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, message, _args, guildData, userData, isSlashCommand) { const pickedSong = songList[Math.floor(Math.random() * songList.length)]; - return require("../music/play.js").run(client, message, [pickedSong], guildData, userData, isSlashCommand); + return require("../music/play").run(client, message, [pickedSong], guildData, userData, isSlashCommand); } } as Command; diff --git a/commands/testcommands/testbot.ts b/commands/testcommands/testbot.ts index d70a1a2..5ed983a 100644 --- a/commands/testcommands/testbot.ts +++ b/commands/testcommands/testbot.ts @@ -1,13 +1,10 @@ import { Command } from "../../types/command"; -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder } = require("discord.js"); -const fs = require("fs"); - module.exports = { ignore: true, description: "Command for testing all the bot's features", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // FIXME pls, I think I selected the wrong type message.deferReply({ ephemeral: true }); return null; diff --git a/commands/testcommands/uptime.ts b/commands/testcommands/uptime.ts index 5b82e4f..3e7448b 100644 --- a/commands/testcommands/uptime.ts +++ b/commands/testcommands/uptime.ts @@ -5,7 +5,7 @@ const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { "description": "Shows the uptime of the bot", - async run(client, message, args, guildData, userData, isSlashCommand) { + async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { const days = Math.floor(client.uptime / 86400000); const hours = Math.floor(client.uptime / 3600000) % 24; const minutes = Math.floor(client.uptime / 60000) % 60; diff --git a/config.ts b/config.ts index 464394a..7e5c4f6 100644 --- a/config.ts +++ b/config.ts @@ -5,7 +5,7 @@ import Client from "./types/client"; module.exports.prefix = process.env.PREFIX; -module.exports.fetchData = require("./functions/fetchDataFromSave.js"); +module.exports.fetchData = require("./functions/fetchDataFromSave"); module.exports.authorsString = ""; const { authors } = require("./package.json"); diff --git a/events/discord/guildCreate.ts b/events/discord/guildCreate.ts index 63fa67a..c025776 100644 --- a/events/discord/guildCreate.ts +++ b/events/discord/guildCreate.ts @@ -1,8 +1,8 @@ // @ts-ignore -import guildModel from "../../schemas/guild.js"; +import guildModel from "../../schemas/guild"; import { Guild, ApplicationCommandDataResolvable } from "discord.js"; -import Client from "../../types/client.js"; +import Client from "../../types/client"; module.exports = async (client: Client, guild: Guild) => { const sus = await guildModel.findOne({ guildId: guild.id }); diff --git a/events/discord/guildDelete.ts b/events/discord/guildDelete.ts index de5382e..dd24667 100644 --- a/events/discord/guildDelete.ts +++ b/events/discord/guildDelete.ts @@ -1,7 +1,7 @@ -import guildModel from "../../schemas/guild.js"; +import guildModel from "../../schemas/guild"; import { Guild, ApplicationCommandDataResolvable } from "discord.js"; -import Client from "../../types/client.js"; +import Client from "../../types/client"; module.exports = async (client: Client, guild: Guild) => { console.info("Deleting MongoDB entry for guild " + guild.name); diff --git a/events/discord/guildMemberAdd.ts b/events/discord/guildMemberAdd.ts index 1ae0baa..e19fc94 100644 --- a/events/discord/guildMemberAdd.ts +++ b/events/discord/guildMemberAdd.ts @@ -1,7 +1,7 @@ import Client from "../../types/client"; import { GuildMember } from "discord.js"; -const fetchData = require("../../config.js").fetchData; +const fetchData = require("../../config").fetchData; const welcomeMessages = fetchData.get("messages").welcome; import guilds from "../../schemas/guild"; diff --git a/events/discord/guildMemberRemove.ts b/events/discord/guildMemberRemove.ts index cb4a8d9..f695775 100644 --- a/events/discord/guildMemberRemove.ts +++ b/events/discord/guildMemberRemove.ts @@ -1,7 +1,7 @@ import Client from "../../types/client"; import { GuildMember } from "discord.js"; -const fetchData = require("../../config.js").fetchData; +const fetchData = require("../../config").fetchData; const goodbyeMessages = fetchData.get("messages").goodbye; import guilds from "../../schemas/guild"; diff --git a/events/discord/ready.ts b/events/discord/ready.ts index f15d294..178dea5 100644 --- a/events/discord/ready.ts +++ b/events/discord/ready.ts @@ -1,4 +1,4 @@ -import Client from "../../types/client.js"; +import Client from "../../types/client"; module.exports = (client: Client) => { client.user.setActivity(`${client.config.prefix}help`); diff --git a/functions/checkChannelID.ts b/functions/checkChannelID.ts index 77aa1ba..b509528 100644 --- a/functions/checkChannelID.ts +++ b/functions/checkChannelID.ts @@ -1,6 +1,6 @@ import { Guild, Message } from "discord.js"; -const fetchData = require("./fetchDataFromSave.js"); +const fetchData = require("./fetchDataFromSave"); module.exports = (message: Message, guildData: any) => { if (guildData?.channels?.allowed === void 0) return true; diff --git a/functions/counter.ts b/functions/counter.ts index 5240d2a..91fe813 100644 --- a/functions/counter.ts +++ b/functions/counter.ts @@ -9,7 +9,8 @@ module.exports = (message: Message, guildData: any) => { const current = guildData.counter.current; if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: any) => { - if (err) console.log(err); + if (err) console.error(err); + (err); if (!data) return "No data found" }); else message.delete().catch(); diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index ae68889..66d8223 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -1,6 +1,6 @@ import { PermissionResolvable, Message } from "discord.js"; -import { Command, CommandReturnWithoutString } from "../types/command.js"; -import Client from "../types/client.js"; +import { Command, CommandReturnWithoutString } from "../types/command"; +import Client from "../types/client"; // TODO: Add automated argument checking @@ -12,7 +12,6 @@ import sendMessage from "./sendMessage"; module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { - console.log(interaction) if (command === void 0) return; // @ts-expect-error @@ -44,11 +43,11 @@ module.exports = async (command: Command, client: Client, interaction: Mes // makes reply unavailable so two replies can't be sent const reply = interaction.reply; - interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand.js. Use return or message.channel.send() instead!") }; + interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand. Use return or message.channel.send() instead!") }; // @ts-expect-error const deferReply = interaction.deferReply; // @ts-expect-error - interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand.js. Use return null instead!") }; + interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand. Use return null instead!") }; try { if (command!.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); diff --git a/functions/fetchDataFromSave.ts b/functions/fetchDataFromSave.ts index c314bdd..5ca5d47 100644 --- a/functions/fetchDataFromSave.ts +++ b/functions/fetchDataFromSave.ts @@ -1,4 +1,5 @@ const data = require("../data.json"); +import fs from "fs"; module.exports = { all: () => { diff --git a/functions/getFiles.ts b/functions/getFiles.ts index 0ed903a..c3ba339 100644 --- a/functions/getFiles.ts +++ b/functions/getFiles.ts @@ -6,9 +6,9 @@ const getFiles = (dir: string, exclude = null) => { if (fs.lstatSync(dir + "/" + path).isDirectory()) { output[path] = getFiles(dir + "/" + path, exclude); } else { - if (!path.endsWith(".js")) return; + if (!path.endsWith(".js") && !path.endsWith(".ts")) return; const func = require(`.${dir}/${path}`); - output[path.replace(".js", "")] = func; + output[path.replace(".js", "").replace(".ts", "")] = func; } }); return output; diff --git a/index.ts b/index.ts index c57501a..378680f 100644 --- a/index.ts +++ b/index.ts @@ -35,7 +35,7 @@ console.log(`Version: ${client.config.version} by ${client.config.authorsString} /* Loading all the functions. */ // @ts-expect-error -global.functions = require("./functions/getFiles")("./functions", "functions.js"); +global.functions = require("./functions/getFiles")("./functions", "functions.ts"); /* Loading all the commands. */ [ @@ -44,8 +44,6 @@ global.functions = require("./functions/getFiles")("./functions", "functions.js" "selectMenus" ].forEach((name) => loadCommands(name, true)); -console.log(client.commands) - client.commandCooldowns = new Collection(); client.commands.forEach((command: Command) => { client.commandCooldowns.set(command.name!, new Collection()); @@ -64,7 +62,7 @@ fs.readdirSync("./events").forEach((dir: string) => { if (!eventToClientMap[dir]) return console.warn(`The event folder ${dir} is not valid!`); console.log(`Loading ${dir} events...`); - fs.readdirSync(`./events/${dir}`).filter((e: string) => e.endsWith(".js")).forEach((event: string) => { + fs.readdirSync(`./events/${dir}`).filter((e: string) => e.endsWith(".ts")).forEach((event: string) => { // @ts-expect-error eventToClientMap[dir].on(event.split(".")[0], require(`./events/${dir}/${event}`).bind(null, client)); }); @@ -92,11 +90,11 @@ function loadCommands(dirName: string, removeTrailingS = true) { fs.readdirSync(`./${dirName}`).forEach((dir: string) => { if (!fs.lstatSync(`./${dirName}/` + dir).isDirectory()) return console.warn(`./${dirName}/${dir} is not a directory.`); - fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".js")).forEach((file: string) => { + fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { const command = require(`./${dirName}/${dir}/${file}`); if (command.ignore) return; command.category = `${dirNameCollection}:` + dir; - command.name ||= file.replace(/(\.js)$/, ""); + command.name ||= file.replace(/(\.ts)$/, ""); command.name = `${dirNameCollection}:` + command.name.toLowerCase(); client.commands.set(command.name, command); }) diff --git a/music/player.js b/music/player.js new file mode 100644 index 0000000..18f061b --- /dev/null +++ b/music/player.js @@ -0,0 +1,356 @@ +const { createAudioPlayer, createAudioResource, joinVoiceChannel, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); +const { stream: AudioStream, video_basic_info, search, yt_validate } = require("play-dl"); +const { ImprovedArray } = require("sussy-util"); +const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } = require("discord.js"); + +const playerControls = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId('command:queue') + .setLabel('☰') + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId('play_pause') + .setLabel('׀׀') + .setStyle(ButtonStyle.Success), + new ButtonBuilder() + .setCustomId('command:stop') + .setLabel('◼') + .setStyle(ButtonStyle.Danger), + new ButtonBuilder() + .setCustomId('command:skip') + .setLabel('>>') + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId('support') + .setLabel('Support us!') + .setStyle(ButtonStyle.Secondary), + ); + +module.exports = class Player { + //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? + //TODO: Add previous function --> Completely rewrite the queue system + //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) + //TODO: Add Spotify support + //TODO: Add Soundcloud support + //TODO: Don't get sued by YouTube + //TODO: Complete rewrite of the player + //BUG: See issue #17 + + #queue = new Map(); + #client; + + constructor(client) { + this.#client = client; + + this.#client.on("voiceStateUpdate", (oldState, newState) => { + const queue = this.getQueue(newState.guild.id); + + if (queue === undefined || oldState.channelId === null) { + return; + } + + if (oldState.id !== this.#client.user.id) { + if (this.#channelEmpty(oldState.channelId)) { + queue.current.channel.send("Leaving channel because it is empty."); + this.#destroyQueue(newState.guild.id); + } + return; + } + if (newState.channelId === undefined) { + queue.current.channel.send("I have been kicked from the channel."); + this.#destroyQueue(newState.guild.id); + } + + if (oldState.channelId !== newState.channelId) { + queue.voiceChannel = newState.channelId; + client.voiceChannel = newState.channelId; + } + }); + } + + #newQueue(guildId) { + this.#queue.set(guildId, { + connection: null, + voiceChannel: null, + player: null, + current: null, + loop: false, + guildId: null, + queue: new ImprovedArray() + }); + } + + #destroyQueue(guildId) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === undefined) return; + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + } + guildInfo.connection.destroy(); + this.#queue.delete(guildId); + } + + async play(guildId, track) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === undefined) return; + guildInfo.current = track; + + const stream = await AudioStream(track.url); + const resource = createAudioResource(stream.stream, { inputType: stream.type }); + + guildInfo.player.play(resource); + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + } + guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); + } + + async #createEmbed(info, type) { + const embed = new EmbedBuilder() + .setURL(info.url) + .setColor(Colors.Red) + .setTimestamp(new Date()) + .setFooter(this.#client.config.embedFooter(this.#client)); + + if (info.title) { + embed.setTitle(`${type} track ${info.title}`); + } + + if (info.thumbnails) { + const thumbnail = info.thumbnails[info.thumbnails.length - 1]; + if (thumbnail) { + embed.setImage(thumbnail.url); + } + } + + return embed; + } + + async addTrack(message, args) { + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + + let videoName = args.map(e => e.trim()).join(" ").trim(); + + if (videoName === "") return "Please enter the link/name of the track"; + + let url; + if (videoName.startsWith("https") && yt_validate(videoName) === "video") { + url = videoName; + } else { + const yt_infos = await search(args.join(" "), { limit: 10 }); + let currentInfo = 0; + do { + url = yt_infos[currentInfo].url; + currentInfo++; + } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); + } + + let info; + try { + info = (await video_basic_info(url)).video_details; + } catch (err) { + + } + if (info === undefined) { + if (this.#queue.get(message.guild.id)?.queue.length === 0) return; + let returnValue = this.skip(message); + returnValue.content = "Can't play tracks requiring age verification! Skipping..."; + return returnValue; + } + + if (!this.#queue.has(message.guild.id)) { + this.#newQueue(message.guild.id); + const queue = this.#queue.get(message.guild.id); + const connection = joinVoiceChannel({ + channelId: message.member.voice.channel.id, + guildId: message.guild.id, + adapterCreator: message.guild.voiceAdapterCreator + }); + + const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); + connection.subscribe(player); + + queue.connection = connection; + queue.player = player; + queue.voiceChannel = message.member.voice.channel.id; + this.#client.voiceChannel = message.member.voice.channel.id; + queue.guildId = message.guild.id; + + queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { + try { + await Promise.race([ + entersState(connection, VoiceConnectionStatus.Signalling, 5_000), + entersState(connection, VoiceConnectionStatus.Connecting, 5_000), + ]); + } catch (error) { + this.#destroyQueue(queue.guildId); + return "There was an error connecting to the voice channel."; + } + }); + + queue.player.on("error", (err) => { + message.channel.send("An error occurred while playing the track."); + this.#destroyQueue(message.guild.id); + }); + + queue.player.on(AudioPlayerStatus.Idle, () => { + if (queue.loop) queue.queue.push(queue.current); + const queueElement = queue.queue.shift(); + if (queueElement === undefined) { + this.#destroyQueue(message.guild.id); + return { content: "Played all tracks leaving the channel.", announce: true }; + } + this.play(message.guild.id, queueElement); + }); + + this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + return "Started playing track!"; + } + + const queue = this.#queue.get(message.guild.id); + + if (queue.voiceChannel !== message.member.voice.channel.id) { + return "You have to be in the same voice channel as the bot to add new tracks."; + } + + queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); + } + + skip(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to skip tracks."; + + const queueElement = queue.queue.shift(); + + if (queueElement === undefined && !queue.loop) { + if (queue.loop) { + this.play(message.guild.id, queueElement || queue.current); + } else { + this.#destroyQueue(message.guild.id); + } + return { content: "Skipped last track. Leaving channel!", announce: true }; + } else { + this.play(message.guild.id, queueElement || queue.current); + return { content: "Skipped track.", announce: true }; + } + } + + stop(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to stop the bot."; + + this.#destroyQueue(message.guild.id); + return { content: "Leaving channel.", announce: true }; + } + + shuffle(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to shuffle the queue."; + + queue.queue.shuffle(); + return { content: "Shuffled the Queue.", announce: true }; + } + + getQueue(guildId) { + return this.#queue.get(guildId); + } + + getCurrent(guildId) { + return this.#queue.get(guildId)?.current; + } + + clearQueue(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to clear the queue."; + + queue.queue.clear(); + return { content: "Cleared queue.", announce: true }; + } + + #channelEmpty(channelId) { + return this.#client.channels.cache.get(channelId)?.members.filter((member) => !member.user.bot).size === 0; + } + + troll(message) { + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return; + queue.queue.clear(); + /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ + this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); + } + + toggleLoop(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to toggle looping."; + + queue.loop = !queue.loop; + if (queue.loop) { + return { content: "Looping is now enabled.", announce: true }; + } else { + return { content: "Looping is now disabled.", announce: true }; + } + } + + pause(message) { + if (message.member.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "There is nothing playing"; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to pause the track"; + + if (queue.player.state.status == "playing") { + queue.player.pause(); + return { content: "The track has been paused", announce: true }; + } else if (queue.player.state.status == "paused") { + return "The track is already paused"; + } + } + + resume(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to pause"; + + if (queue.player.state.status == "paused") { + queue.player.unpause(); + return { content: "The track has been resumed", announce: true }; + } else if (queue.player.state.status == "playing") { + return "The track is already playing"; + } + } +}; + +async function isAgeRestricted(url) { + try { + (await video_basic_info(url)).video_details; + } catch (err) { + return true; + } + return false; +} diff --git a/music/player.ts b/music/player.ts.ignore similarity index 100% rename from music/player.ts rename to music/player.ts.ignore diff --git a/package.json b/package.json index b6444fa..4067ffe 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,11 @@ "name": "sus-bot", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "index.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "(tsc || true) && node index.js" + "start": "ts-node index.ts", + "jsStart": "(tsc || true) && node index.js" }, "repository": { "type": "git", diff --git a/tsconfig.json b/tsconfig.json index 0d8bfbb..89ec989 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,7 +32,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ + "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ diff --git a/tslint-to-eslint-config.log b/tslint-to-eslint-config.log new file mode 100644 index 0000000..99e8ce9 --- /dev/null +++ b/tslint-to-eslint-config.log @@ -0,0 +1,4 @@ +1 ESLint rule behaves differently from its TSLint counterpart: + * @typescript-eslint/no-unused-expressions: + - The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored. + diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..059fff1 --- /dev/null +++ b/tslint.json @@ -0,0 +1,13 @@ +{ + "rules": { + "no-unused-expression": true, + "no-duplicate-variable": true, + "class-name": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": true + }, + "defaultSeverity": "warning" +} \ No newline at end of file diff --git a/types/client.ts b/types/client.ts index 5dbd45e..8a61afb 100644 --- a/types/client.ts +++ b/types/client.ts @@ -1,5 +1,5 @@ import { Client as DiscordClient, Collection } from "discord.js"; -import { Command } from "./command.js"; +import { Command } from "./command"; // @ts-ignore: Unreachable code error import Player from "../music/player"; import { connection } from "mongoose"; diff --git a/types/command.ts b/types/command.ts index 342502d..d202795 100644 --- a/types/command.ts +++ b/types/command.ts @@ -1,5 +1,5 @@ import { CommandInteraction, ApplicationCommandOption, CacheType, Message, InteractionReplyOptions, MessageReplyOptions } from "discord.js"; -import Client from "./client.js"; +import Client from "./client"; export interface Command { ignore?: boolean; From 54a48adecc3b68bfd3ebf1b7ffd98dd7e2cfb146 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 2 Feb 2023 13:08:51 +0100 Subject: [PATCH 13/28] replaced spaces with tabs --- buttons/economy/resetBalance.ts | 12 +- buttons/economy/resetLevel.ts | 10 +- buttons/economy/search.ts | 26 +- buttons/general/support.ts | 44 +- buttons/music/play_pause.ts | 24 +- commands/economy/balance.ts | 10 +- commands/economy/bet.ts | 112 ++-- commands/economy/deposit.ts | 72 +-- commands/economy/job.ts | 146 ++--- commands/economy/level.ts | 44 +- commands/economy/resetBalance.ts | 58 +- commands/economy/resetLevel.ts | 58 +- commands/economy/search.ts | 274 ++++---- commands/economy/withdraw.ts | 48 +- commands/economy/work.ts | 60 +- commands/games/coinflip.ts | 40 +- commands/games/numberguess.ts | 66 +- commands/general/help.ts | 148 ++--- commands/general/info.ts | 50 +- commands/general/invite.ts | 18 +- commands/general/inviteBot.ts | 8 +- commands/general/serverinfo.ts | 26 +- commands/general/userinfo.ts | 50 +- commands/moderation/clear.ts | 136 ++-- commands/moderation/lock.ts | 68 +- commands/moderation/nickname.ts | 70 +- commands/moderation/prepare.ts | 42 +- commands/moderation/remove-nickname.ts | 46 +- commands/moderation/set-counter-channel.ts | 48 +- commands/moderation/set-goodbye-channel.ts | 48 +- commands/moderation/set-welcome-channel.ts | 48 +- commands/moderation/slowmode.ts | 74 +-- commands/moderation/tempban.ts | 40 +- commands/moderation/unban.ts | 62 +- commands/moderation/unlock.ts | 68 +- commands/music/clearQueue.ts | 14 +- commands/music/loop.ts | 16 +- commands/music/nowPlaying.ts | 30 +- commands/music/pause.ts | 16 +- commands/music/play.ts | 32 +- commands/music/queue.ts | 40 +- commands/music/resume.ts | 16 +- commands/music/shuffle.ts | 16 +- commands/music/skip.ts | 16 +- commands/music/stop.ts | 16 +- commands/music/troll.ts | 26 +- commands/testcommands/ping.ts | 64 +- commands/testcommands/playtest.ts | 114 ++-- commands/testcommands/testbot.ts | 14 +- commands/testcommands/uptime.ts | 30 +- config.ts | 4 +- enums/permissionBitField.ts | 82 +-- enums/permissionStrings.ts | 82 +-- events/discord/guildCreate.ts | 18 +- events/discord/guildDelete.ts | 4 +- events/discord/guildMemberAdd.ts | 10 +- events/discord/messageCreate.ts | 46 +- events/discord/ready.ts | 6 +- events/mongodb/connected.ts | 4 +- events/mongodb/connecting.ts | 2 +- events/mongodb/disconnected.ts | 2 +- events/mongodb/err.ts | 2 +- functions/addGuildDocument.ts | 30 +- functions/addUserDocument.ts | 8 +- functions/checkChannelID.ts | 16 +- functions/convertTime.ts | 46 +- functions/counter.ts | 24 +- functions/executeCommand.ts | 352 +++++----- functions/fetchDataFromSave.ts | 28 +- functions/formatCommandReturn.ts | 46 +- functions/getChannelFromMention.ts | 4 +- functions/getFiles.ts | 22 +- functions/getGuildData.ts | 12 +- functions/getUserData.ts | 12 +- functions/replaceUser.ts | 2 +- functions/sendMessage.ts | 114 ++-- functions/shuffle.ts | 12 +- index.ts | 76 +-- music/player.js | 686 ++++++++++---------- music/player.ts.ignore | 708 ++++++++++----------- schemas/guild.ts | 40 +- schemas/user.ts | 24 +- selectMenus/general/help.ts | 8 +- types/client.ts | 26 +- types/command.ts | 50 +- www/index.ts | 12 +- www/routes/commands.ts | 32 +- www/routes/logo.ts | 10 +- www/static/commands/index.ts | 40 +- 89 files changed, 2657 insertions(+), 2659 deletions(-) diff --git a/buttons/economy/resetBalance.ts b/buttons/economy/resetBalance.ts index c1c01d9..fa36cca 100644 --- a/buttons/economy/resetBalance.ts +++ b/buttons/economy/resetBalance.ts @@ -3,10 +3,10 @@ import { Component } from "../../types/command"; import userList from "../../schemas/user"; module.exports = { - run(_client, _interaction, _args, _guildData, userData) { - userData.economy.wallet = 0; - userData.economy.bank = 0; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { err; data; }); - return { content: "Your balance has been reset!", disableOriginal: true }; - } + run(_client, _interaction, _args, _guildData, userData) { + userData.economy.wallet = 0; + userData.economy.bank = 0; + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { err; data; }); + return { content: "Your balance has been reset!", disableOriginal: true }; + } } as Component; \ No newline at end of file diff --git a/buttons/economy/resetLevel.ts b/buttons/economy/resetLevel.ts index b4f2aae..a689f02 100644 --- a/buttons/economy/resetLevel.ts +++ b/buttons/economy/resetLevel.ts @@ -3,9 +3,9 @@ import { Component } from "../../types/command"; const userList = require("../../schemas/user"); module.exports = { - run(_client, _interaction, _args, _guildData, userData) { - userData.level.xp = 0; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); - return { content: "Your level has been reset!", disableOriginal: true }; - } + run(_client, _interaction, _args, _guildData, userData) { + userData.level.xp = 0; + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); + return { content: "Your level has been reset!", disableOriginal: true }; + } } as Component; \ No newline at end of file diff --git a/buttons/economy/search.ts b/buttons/economy/search.ts index cb8d1d6..f9c893b 100644 --- a/buttons/economy/search.ts +++ b/buttons/economy/search.ts @@ -4,17 +4,17 @@ import userList from "../../schemas/user"; import { Random } from "sussy-util"; module.exports = { - name: "search", - commandOptions: { - cooldown: 60 - }, - async run(_client, _interaction, args, _guildData, userData) { - const amount = Random.randomInt(900, 1600); - const current = userData.economy; - current.wallet += amount; - userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { err; data; }); - userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); - return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; - } + name: "search", + commandOptions: { + cooldown: 60 + }, + async run(_client, _interaction, args, _guildData, userData) { + const amount = Random.randomInt(900, 1600); + const current = userData.economy; + current.wallet += amount; + userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { err; data; }); + userData.level.xp += 2; + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); + return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; + } } as Component; \ No newline at end of file diff --git a/buttons/general/support.ts b/buttons/general/support.ts index 4af702b..7c20f91 100644 --- a/buttons/general/support.ts +++ b/buttons/general/support.ts @@ -3,26 +3,26 @@ import { Component } from "../../types/command"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; module.exports = { - run(_client, _interaction) { - const choice = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setLabel('GitHub') - .setStyle(ButtonStyle.Link) - .setURL('https://github.com/plastik_flasche/SUS-Bot'), - new ButtonBuilder() - .setLabel('Patreon') - .setStyle(ButtonStyle.Link) - .setURL('https://patreon.com/stupid-useless-patreon'), - new ButtonBuilder() - .setLabel('PayPal') - .setStyle(ButtonStyle.Link) - .setURL('https://paypal.me/stupiduselesspaypal'), - // new ButtonBuilder() - // .setLabel('Crypto') - // .setStyle('LINK') - // .setURL('') - ); - return { content: 'If you can code, help us out on our Github, if not, maybe buy us some more processing power!', components: [choice] }; - } + run(_client, _interaction) { + const choice = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('GitHub') + .setStyle(ButtonStyle.Link) + .setURL('https://github.com/plastik_flasche/SUS-Bot'), + new ButtonBuilder() + .setLabel('Patreon') + .setStyle(ButtonStyle.Link) + .setURL('https://patreon.com/stupid-useless-patreon'), + new ButtonBuilder() + .setLabel('PayPal') + .setStyle(ButtonStyle.Link) + .setURL('https://paypal.me/stupiduselesspaypal'), + // new ButtonBuilder() + // .setLabel('Crypto') + // .setStyle('LINK') + // .setURL('') + ); + return { content: 'If you can code, help us out on our Github, if not, maybe buy us some more processing power!', components: [choice] }; + } } as Component; diff --git a/buttons/music/play_pause.ts b/buttons/music/play_pause.ts index b3de31b..d29b6e4 100644 --- a/buttons/music/play_pause.ts +++ b/buttons/music/play_pause.ts @@ -1,16 +1,16 @@ import { Component } from "../../types/command"; module.exports = { - commandOptions: { - connectedToSameVC: true - }, - run(client, interaction) { - let returnValue = client.player.pause(interaction); - if (returnValue !== "The track is already paused") { - return returnValue; - } else { - returnValue = client.player.resume(interaction); - } - return returnValue; - } + commandOptions: { + connectedToSameVC: true + }, + run(client, interaction) { + let returnValue = client.player.pause(interaction); + if (returnValue !== "The track is already paused") { + return returnValue; + } else { + returnValue = client.player.resume(interaction); + } + return returnValue; + } } as Component; diff --git a/commands/economy/balance.ts b/commands/economy/balance.ts index c6ae1eb..0565497 100644 --- a/commands/economy/balance.ts +++ b/commands/economy/balance.ts @@ -1,11 +1,11 @@ import { Command } from "../../types/command"; module.exports = { - description: "Shows the balance of your money", - aliases: ["bal"], + description: "Shows the balance of your money", + aliases: ["bal"], - run(_client, _message, _args, _guildData, userData, _isSlashCommand) { - return "You have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; - } + run(_client, _message, _args, _guildData, userData, _isSlashCommand) { + return "You have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; + } } as Command; diff --git a/commands/economy/bet.ts b/commands/economy/bet.ts index cf779dc..ad0da41 100644 --- a/commands/economy/bet.ts +++ b/commands/economy/bet.ts @@ -5,64 +5,64 @@ import { EmbedBuilder } from "discord.js"; import { IsSomething } from "sussy-util"; module.exports = { - description: "Bet your money and win!", + description: "Bet your money and win!", - run(client, _message, args, _guildData, userData, _isSlashCommand) { + run(client, _message, args, _guildData, userData, _isSlashCommand) { - const embed = new EmbedBuilder() - .setTimestamp(new Date()) - .setTitle("Casino") - // @ts-expect-error - .setFooter(client.config.embedFooter(client)); + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Casino") + // @ts-expect-error + .setFooter(client.config.embedFooter(client)); - if (!(IsSomething.isNumber(args[0]))) { - embed.addFields( - { - name: "Bet failed!", - value: "Please enter a valid number", - inline: true - } - ); - } - else if (args[0] > userData.economy.wallet) { - embed.addFields( - { - name: "Bet failed!", - value: "Please enter a number less than or equal to your wallet", - inline: true - } - ); - } - else { - const random = Math.round((Math.random())); + if (!(IsSomething.isNumber(args[0]))) { + embed.addFields( + { + name: "Bet failed!", + value: "Please enter a valid number", + inline: true + } + ); + } + else if (args[0] > userData.economy.wallet) { + embed.addFields( + { + name: "Bet failed!", + value: "Please enter a number less than or equal to your wallet", + inline: true + } + ); + } + else { + const random = Math.round((Math.random())); - switch (random) { - case 0: - userData.economy.wallet -= +args[0]; - embed.addFields( - { - name: "You Lost!", - value: "Oh No! You lost " + args[0] + " gold!", - inline: true - } - ); - break; - default: - userData.economy.wallet += args[0]; - embed.addFields( - { - name: "You won!", - value: "Congratulations! You won " + args[0] + " gold!", - inline: true - } - ); - break; - } - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - } - return { embeds: [embed] }; - } + switch (random) { + case 0: + userData.economy.wallet -= +args[0]; + embed.addFields( + { + name: "You Lost!", + value: "Oh No! You lost " + args[0] + " gold!", + inline: true + } + ); + break; + default: + userData.economy.wallet += args[0]; + embed.addFields( + { + name: "You won!", + value: "Congratulations! You won " + args[0] + " gold!", + inline: true + } + ); + break; + } + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + } + return { embeds: [embed] }; + } } as Command; diff --git a/commands/economy/deposit.ts b/commands/economy/deposit.ts index 9313e5c..3ed339c 100644 --- a/commands/economy/deposit.ts +++ b/commands/economy/deposit.ts @@ -5,40 +5,40 @@ const { IsSomething } = require("sussy-util"); const users = require("../../schemas/user"); module.exports = { - description: "Deposit money into your bank account", - aliases: ["dep"], - - options: [ - { - name: "amount", - description: "max / Amount to deposit", - type: ApplicationCommandOptionType.String, - required: true - } - ], - - - run: (_client, _message, args, _guildInfo, userInfo) => { - if (!args[0]) return "Please provide the amount you want to deposit."; - - const current = userInfo.economy; - let moneys = current.wallet; - - if (args[0] === "max") { - current.bank += current.wallet; - current.wallet = 0; - } else { - if (!IsSomething.isNumber(args[0])) return "Please provide the amount you want to deposit as a number."; - if (+args[0] > current.wallet) return "You do not have enough money to deposit " + args[0] + " gold."; - current.bank += +args[0]; - current.wallet -= +args[0]; - moneys = +args[0]; - } - - users.findByIdAndUpdate(userInfo._id, { economy: current }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return `Deposited ${moneys} gold.`; - } + description: "Deposit money into your bank account", + aliases: ["dep"], + + options: [ + { + name: "amount", + description: "max / Amount to deposit", + type: ApplicationCommandOptionType.String, + required: true + } + ], + + + run: (_client, _message, args, _guildInfo, userInfo) => { + if (!args[0]) return "Please provide the amount you want to deposit."; + + const current = userInfo.economy; + let moneys = current.wallet; + + if (args[0] === "max") { + current.bank += current.wallet; + current.wallet = 0; + } else { + if (!IsSomething.isNumber(args[0])) return "Please provide the amount you want to deposit as a number."; + if (+args[0] > current.wallet) return "You do not have enough money to deposit " + args[0] + " gold."; + current.bank += +args[0]; + current.wallet -= +args[0]; + moneys = +args[0]; + } + + users.findByIdAndUpdate(userInfo._id, { economy: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return `Deposited ${moneys} gold.`; + } } as Command; \ No newline at end of file diff --git a/commands/economy/job.ts b/commands/economy/job.ts index e95c820..f99a8ea 100644 --- a/commands/economy/job.ts +++ b/commands/economy/job.ts @@ -7,82 +7,82 @@ const jobs = require("./resources/jobs.json").jobs; const { IsSomething } = require("sussy-util"); module.exports = { - description: "Panel which shows jobs", - aliases: ["jobs"], - options: [{ - name: "JobID", - type: ApplicationCommandOptionType.Integer, - description: "ID of the job to switch to", - required: false, - }], + description: "Panel which shows jobs", + aliases: ["jobs"], + options: [{ + name: "JobID", + type: ApplicationCommandOptionType.Integer, + description: "ID of the job to switch to", + required: false, + }], - run(client, _message, args, _guildData, userData) { - if (args[0] === void 0) { - const embed = new EmbedBuilder() - .setTimestamp(new Date()) - .setTitle("Jobs panel") - // @ts-expect-error - .setFooter(client.config.embedFooter(client)) - .addFields( - { - name: "Current Job", - value: jobs[userData.jobinfo.id - 1].jobname + "", - inline: true - }, - { - name: "Salary", - value: jobs[userData.jobinfo.id - 1].salary + "", - inline: true - }, - { - name: "Level required", - value: jobs[userData.jobinfo.id - 1].reqlevel + "", - inline: true - } - ); + run(client, _message, args, _guildData, userData) { + if (args[0] === void 0) { + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Jobs panel") + // @ts-expect-error + .setFooter(client.config.embedFooter(client)) + .addFields( + { + name: "Current Job", + value: jobs[userData.jobinfo.id - 1].jobname + "", + inline: true + }, + { + name: "Salary", + value: jobs[userData.jobinfo.id - 1].salary + "", + inline: true + }, + { + name: "Level required", + value: jobs[userData.jobinfo.id - 1].reqlevel + "", + inline: true + } + ); - for (let i = 0; i < jobs.length; i++) { - if (!(userData.jobinfo.id === (i + 1))) { - embed.addFields( - { - name: "JobID: " + (i + 1), - value: jobs[i].jobname + "", - inline: true - }, - { - name: "Salary:", - value: jobs[i].salary + "", - inline: true - }, - { - name: "Required Level:", - value: jobs[i].reqlevel + "", - inline: true - } - ); - } + for (let i = 0; i < jobs.length; i++) { + if (!(userData.jobinfo.id === (i + 1))) { + embed.addFields( + { + name: "JobID: " + (i + 1), + value: jobs[i].jobname + "", + inline: true + }, + { + name: "Salary:", + value: jobs[i].salary + "", + inline: true + }, + { + name: "Required Level:", + value: jobs[i].reqlevel + "", + inline: true + } + ); + } - } + } - return { embeds: [embed] }; - } else { - const currentID = userData.jobinfo.id; - if (!IsSomething.isNumber(+args[0])) - return "Provide a valid number as job ID"; - if (currentID === +args[0]) - return "You are already a " + jobs[currentID - 1].jobname; - if (+args[0] <= 0 || args[0] > jobs.length) - return "Bad ID"; - if (Math.floor(userData.level.xp / 50) < (jobs[+args[0] - 1].reqlevel)) { - return "Level too low for this job"; - } + return { embeds: [embed] }; + } else { + const currentID = userData.jobinfo.id; + if (!IsSomething.isNumber(+args[0])) + return "Provide a valid number as job ID"; + if (currentID === +args[0]) + return "You are already a " + jobs[currentID - 1].jobname; + if (+args[0] <= 0 || args[0] > jobs.length) + return "Bad ID"; + if (Math.floor(userData.level.xp / 50) < (jobs[+args[0] - 1].reqlevel)) { + return "Level too low for this job"; + } - userData.jobinfo.id = args[0]; - userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return "Congratulations! You are now a " + jobs[userData.jobinfo.id - 1].jobname; - } - } + userData.jobinfo.id = args[0]; + userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return "Congratulations! You are now a " + jobs[userData.jobinfo.id - 1].jobname; + } + } } as Command; diff --git a/commands/economy/level.ts b/commands/economy/level.ts index 60adf26..ab30f80 100644 --- a/commands/economy/level.ts +++ b/commands/economy/level.ts @@ -3,29 +3,29 @@ import { Command } from "../../types/command"; const { IsSomething } = require("sussy-util"); const { EmbedBuilder } = require("discord.js"); module.exports = { - description: "Shows the level of your account", - aliases: ["lvl"], + description: "Shows the level of your account", + aliases: ["lvl"], - run(client, _message, _args, _guildData, userData, _isSlashCommand) { - const embed = new EmbedBuilder() - .setTimestamp(new Date()) - .setTitle("Level panel") - // @ts-expect-error - .setFooter(client.config.embedFooter(client)); + run(client, _message, _args, _guildData, userData, _isSlashCommand) { + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Level panel") + // @ts-expect-error + .setFooter(client.config.embedFooter(client)); - embed.addFields( - { - name: "Level", - value: Math.floor(userData.level.xp / 50) + "", - inline: true - }, - { - name: "XP", - value: (userData.level.xp % 50) + "", - inline: true - }, - ); - return { embeds: [embed] }; - } + embed.addFields( + { + name: "Level", + value: Math.floor(userData.level.xp / 50) + "", + inline: true + }, + { + name: "XP", + value: (userData.level.xp % 50) + "", + inline: true + }, + ); + return { embeds: [embed] }; + } } as Command; diff --git a/commands/economy/resetBalance.ts b/commands/economy/resetBalance.ts index de2b84c..dc3bffb 100644 --- a/commands/economy/resetBalance.ts +++ b/commands/economy/resetBalance.ts @@ -3,36 +3,36 @@ import { Command } from "../../types/command"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); module.exports = { - description: "Clears your balance", - aliases: ["clb", "clearbalance", "resetbalance", "rb", "resetbal", "clearbal"], + description: "Clears your balance", + aliases: ["clb", "clearbalance", "resetbalance", "rb", "resetbal", "clearbal"], - run(client, _message, _args, _guildData, _userData, isInteraction) { - const embed = new EmbedBuilder() - .setTitle("Reset Balance") - .setDescription("Are you sure you want to reset your balance?") - .setColor(Colors.Red) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)); + run(client, _message, _args, _guildData, _userData, isInteraction) { + const embed = new EmbedBuilder() + .setTitle("Reset Balance") + .setDescription("Are you sure you want to reset your balance?") + .setColor(Colors.Red) + // @ts-expect-error // TODO: Fix this + .setFooter(client.config.embedFooter(client)); - if (isInteraction) { - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId("resetBalance") - .setLabel("Confirm") - .setStyle(ButtonStyle.Danger), - ); + if (isInteraction) { + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId("resetBalance") + .setLabel("Confirm") + .setStyle(ButtonStyle.Danger), + ); - return { embeds: [embed], components: [row], timeout: 60 }; - } else { - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId(`resetBalance`) - .setLabel("Confirm") - .setStyle(ButtonStyle.Danger), - ); - return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; - } - } + return { embeds: [embed], components: [row], timeout: 60 }; + } else { + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId(`resetBalance`) + .setLabel("Confirm") + .setStyle(ButtonStyle.Danger), + ); + return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; + } + } } as Command; diff --git a/commands/economy/resetLevel.ts b/commands/economy/resetLevel.ts index 507fe70..b94a0c1 100644 --- a/commands/economy/resetLevel.ts +++ b/commands/economy/resetLevel.ts @@ -3,36 +3,36 @@ import { Command } from "../../types/command"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); module.exports = { - description: "Clears your level", - aliases: ["cll", "clearlevel", "resetlevel", "rl", "resetlvl", "clearlvl"], + description: "Clears your level", + aliases: ["cll", "clearlevel", "resetlevel", "rl", "resetlvl", "clearlvl"], - run(client, _message, _args, _guildData, _userData, isInteraction) { - const embed = new EmbedBuilder() - .setTitle("Reset Level") - .setDescription("Are you sure you want to reset your level?") - .setColor(Colors.Red) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)); + run(client, _message, _args, _guildData, _userData, isInteraction) { + const embed = new EmbedBuilder() + .setTitle("Reset Level") + .setDescription("Are you sure you want to reset your level?") + .setColor(Colors.Red) + // @ts-expect-error + .setFooter(client.config.embedFooter(client)); - if (isInteraction) { - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId("resetLevel") - .setLabel("Confirm") - .setStyle(ButtonStyle.Danger), - ); + if (isInteraction) { + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId("resetLevel") + .setLabel("Confirm") + .setStyle(ButtonStyle.Danger), + ); - return { embeds: [embed], components: [row], timeout: 60 }; - } else { - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId(`resetLevel`) - .setLabel("Confirm") - .setStyle(ButtonStyle.Danger), - ); - return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; - } - } + return { embeds: [embed], components: [row], timeout: 60 }; + } else { + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId(`resetLevel`) + .setLabel("Confirm") + .setStyle(ButtonStyle.Danger), + ); + return { content: "Check your DMs!", DM: { embeds: [embed], components: [row], timeout: 60 } }; + } + } } as Command; \ No newline at end of file diff --git a/commands/economy/search.ts b/commands/economy/search.ts index 3ff69a8..7e74538 100644 --- a/commands/economy/search.ts +++ b/commands/economy/search.ts @@ -5,148 +5,148 @@ const { EmbedBuilder, Colors, ActionRowBuilder, StringSelectMenuBuilder, SelectM const userList = require("../../schemas/user"); module.exports = { - description: "Search in a few places for money.", - commandOptions: { - cooldown: 60 - }, + description: "Search in a few places for money.", + commandOptions: { + cooldown: 60 + }, - run: (_client, _message, _args, _guildData, _userData) => { - const places = [ - "bank", - "river", - "pocket", - "car", - "house", - "garden", - "street", - "park", - "school", - "work", - "shop", - "gym", - "hospital", - "church", - "library", - "mall", - "beach", - "forest", - "mountain", - "cave", - "farm", - "factory", - "office", - "hotel", - "museum", - "zoo", - "casino", - "bar", - "restaurant", - "club", - "parking lot", - "bus stop", - "train station", - "airport", - "police station", - "fire station", - "post office", - "bank", - "supermarket", - "bakery", - "butcher", - "pharmacy", - "hardware store", - "bookstore", - "clothing store", - "jewelry store", - "pet store", - "toy store", - "furniture store", - "car dealership", - "car repair shop", - "car wash", - "gas station", - "laundry", - "dry cleaner", - "hair salon", - "spa", - "tattoo parlor", - "barber shop", - "dentist", - "doctor", - "optician", - "veterinarian", - "golf course", - "bowling alley", - "amusement park", - "movie theater", - "concert hall", - "stadium", - "aquarium", - "circus", - "casino", - "bar", - "restaurant", - "club", - "parking lot", - "bus stop", - "train station", - "airport", - "police station", - "fire station", - "post office", - "bank", - "supermarket", - "bakery", - "butcher", - "pharmacy", - "hardware store", - "bookstore", - "clothing store", - "jewelry store", - "pet store", - "toy store", - "furniture store", - "car dealership", - "car repair shop", - "car wash", - "gas station", - "laundry", - "dry cleaner", - "hair salon", - "spa", - "tattoo parlor", - "barber shop", - "dentist", - "doctor", - "optician", - "veterinarian", - "golf course", - "bowling alley", - "amusement park", - "movie theater", - "concert hall", - "stadium", - "aquarium", - "circus"]; + run: (_client, _message, _args, _guildData, _userData) => { + const places = [ + "bank", + "river", + "pocket", + "car", + "house", + "garden", + "street", + "park", + "school", + "work", + "shop", + "gym", + "hospital", + "church", + "library", + "mall", + "beach", + "forest", + "mountain", + "cave", + "farm", + "factory", + "office", + "hotel", + "museum", + "zoo", + "casino", + "bar", + "restaurant", + "club", + "parking lot", + "bus stop", + "train station", + "airport", + "police station", + "fire station", + "post office", + "bank", + "supermarket", + "bakery", + "butcher", + "pharmacy", + "hardware store", + "bookstore", + "clothing store", + "jewelry store", + "pet store", + "toy store", + "furniture store", + "car dealership", + "car repair shop", + "car wash", + "gas station", + "laundry", + "dry cleaner", + "hair salon", + "spa", + "tattoo parlor", + "barber shop", + "dentist", + "doctor", + "optician", + "veterinarian", + "golf course", + "bowling alley", + "amusement park", + "movie theater", + "concert hall", + "stadium", + "aquarium", + "circus", + "casino", + "bar", + "restaurant", + "club", + "parking lot", + "bus stop", + "train station", + "airport", + "police station", + "fire station", + "post office", + "bank", + "supermarket", + "bakery", + "butcher", + "pharmacy", + "hardware store", + "bookstore", + "clothing store", + "jewelry store", + "pet store", + "toy store", + "furniture store", + "car dealership", + "car repair shop", + "car wash", + "gas station", + "laundry", + "dry cleaner", + "hair salon", + "spa", + "tattoo parlor", + "barber shop", + "dentist", + "doctor", + "optician", + "veterinarian", + "golf course", + "bowling alley", + "amusement park", + "movie theater", + "concert hall", + "stadium", + "aquarium", + "circus"]; - const actionRow = new ActionRowBuilder() + const actionRow = new ActionRowBuilder() - const embed = new EmbedBuilder(true) - .setTitle("Search") - .setColor(Colors.Red) - .setDescription("Where do you want to search?"); + const embed = new EmbedBuilder(true) + .setTitle("Search") + .setColor(Colors.Red) + .setDescription("Where do you want to search?"); - const randomElements = places.sort(() => Math.random() - 0.5).slice(0, 5); + const randomElements = places.sort(() => Math.random() - 0.5).slice(0, 5); - randomElements.forEach(place => { - const button = new ButtonBuilder() - .setLabel(StringUtil.capitalize(place)) - .setCustomId(`search ${place}`) - .setStyle(ButtonStyle.Primary); + randomElements.forEach(place => { + const button = new ButtonBuilder() + .setLabel(StringUtil.capitalize(place)) + .setCustomId(`search ${place}`) + .setStyle(ButtonStyle.Primary); - actionRow.addComponents(button); - }); + actionRow.addComponents(button); + }); - return { embeds: [embed], components: [actionRow] }; - } + return { embeds: [embed], components: [actionRow] }; + } } as Command; \ No newline at end of file diff --git a/commands/economy/withdraw.ts b/commands/economy/withdraw.ts index e172365..10a1ee5 100644 --- a/commands/economy/withdraw.ts +++ b/commands/economy/withdraw.ts @@ -4,29 +4,29 @@ import { ApplicationCommandOptionType } from "discord.js"; const { IsSomething } = require("sussy-util"); const userList = require("../../schemas/user"); module.exports = { - description: "Withdraw money from your bank account", - aliases: ["with", "wth"], - options: [{ - name: "amount", - type: ApplicationCommandOptionType.String, - description: "Amount that will be withdrawn", - required: true, - }], + description: "Withdraw money from your bank account", + aliases: ["with", "wth"], + options: [{ + name: "amount", + type: ApplicationCommandOptionType.String, + description: "Amount that will be withdrawn", + required: true, + }], - run(_client, _message, args, _guildData, userData, _isSlashCommand) { - let amount = args[0]; - if (amount && IsSomething.isNumber(amount)) { - if (amount > userData.economy.bank) amount = userData.economy.bank; - userData.economy.bank -= +amount; - userData.economy.wallet += +amount; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return amount + " withdrawn. You now have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; - } - else { - return "Please specify an amount"; - } - } + run(_client, _message, args, _guildData, userData, _isSlashCommand) { + let amount = args[0]; + if (amount && IsSomething.isNumber(amount)) { + if (amount > userData.economy.bank) amount = userData.economy.bank; + userData.economy.bank -= +amount; + userData.economy.wallet += +amount; + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return amount + " withdrawn. You now have " + userData.economy.wallet + " gold in your wallet and " + userData.economy.bank + " gold in your bank"; + } + else { + return "Please specify an amount"; + } + } } as Command; diff --git a/commands/economy/work.ts b/commands/economy/work.ts index 51c164a..1ac2cc2 100644 --- a/commands/economy/work.ts +++ b/commands/economy/work.ts @@ -5,35 +5,35 @@ const userList = require("../../schemas/user"); const jobs = require("./resources/jobs.json").jobs; module.exports = { - description: "Work to earn money", - aliases: ["wk"], - commandOptions: { - cooldown: 1800 - }, - options: [{ - name: "job", - type: ApplicationCommandOptionType.String, - description: "Job you want to work as", - required: true, - }], + description: "Work to earn money", + aliases: ["wk"], + commandOptions: { + cooldown: 1800 + }, + options: [{ + name: "job", + type: ApplicationCommandOptionType.String, + description: "Job you want to work as", + required: true, + }], - run(_client, message, _args, _guildData, userData, _isSlashCommand) { - if (userData.economy) { - let earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); - userData.economy.wallet += earned; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - userData.level.xp += 5; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - if (!(Math.floor(userData.level.xp / 50) === (Math.floor((userData.level.xp - 5) / 50)))) { - message!.channel!.send(`<@${userData.userId}>` + " just levelled up!") - } - return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", setCooldown: [this] }; - } - } + run(_client, message, _args, _guildData, userData, _isSlashCommand) { + if (userData.economy) { + let earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); + userData.economy.wallet += earned; + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + userData.level.xp += 5; + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + if (!(Math.floor(userData.level.xp / 50) === (Math.floor((userData.level.xp - 5) / 50)))) { + message!.channel!.send(`<@${userData.userId}>` + " just levelled up!") + } + return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", setCooldown: [this] }; + } + } } as Command; diff --git a/commands/games/coinflip.ts b/commands/games/coinflip.ts index 4f6bdde..5a600dd 100644 --- a/commands/games/coinflip.ts +++ b/commands/games/coinflip.ts @@ -2,25 +2,25 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; module.exports = { - aliases: ["flip", "coin"], - description: 'flips a coin', - options: [{ - name: "headsTails", - type: ApplicationCommandOptionType.String, - description: "select heads or tails", - required: false, - }], + aliases: ["flip", "coin"], + description: 'flips a coin', + options: [{ + name: "headsTails", + type: ApplicationCommandOptionType.String, + description: "select heads or tails", + required: false, + }], - run(_client, message, args, _guildData, _userData, _isSlashCommand) { - const coinArray = ["heads", "tails"]; - let numberThrow = Math.floor(Math.random() * 2); - if (!(args[0] === `heads`) && !(args[0] === 'tails')) { - return coinArray[numberThrow]; - } - message!.channel!.send(coinArray[numberThrow]); - if (args[0] === coinArray[numberThrow]) { - return "You are victorious!"; - } - return "You are a loser!"; - } + run(_client, message, args, _guildData, _userData, _isSlashCommand) { + const coinArray = ["heads", "tails"]; + let numberThrow = Math.floor(Math.random() * 2); + if (!(args[0] === `heads`) && !(args[0] === 'tails')) { + return coinArray[numberThrow]; + } + message!.channel!.send(coinArray[numberThrow]); + if (args[0] === coinArray[numberThrow]) { + return "You are victorious!"; + } + return "You are a loser!"; + } } as Command; diff --git a/commands/games/numberguess.ts b/commands/games/numberguess.ts index 1d7f6df..fcc7a19 100644 --- a/commands/games/numberguess.ts +++ b/commands/games/numberguess.ts @@ -3,39 +3,39 @@ import { ApplicationCommandOptionType } from "discord.js"; const { IsSomething } = require("sussy-util"); module.exports = { - aliases: ["number", "guess"], - description: "guess a number between 1 and the specified number", - options: [ - { - name: "number", - type: ApplicationCommandOptionType.Number, - description: "the specified number", - required: true, - }, - { - name: "guess", - type: ApplicationCommandOptionType.Number, - description: "the guessed number", - required: true, - } - ], + aliases: ["number", "guess"], + description: "guess a number between 1 and the specified number", + options: [ + { + name: "number", + type: ApplicationCommandOptionType.Number, + description: "the specified number", + required: true, + }, + { + name: "guess", + type: ApplicationCommandOptionType.Number, + description: "the guessed number", + required: true, + } + ], - run(_client, message, args, _guildData, _userData, _isSlashCommand) { - if (args[0] === void 0 || args[0] === `` || args[1] === void 0 || args[1] === ``) { - return "Please specify two numbers"; - } - if (!(IsSomething.isNumber(args[0])) || !(IsSomething.isNumber(args[1]))) { - return "Both parameters need to be numbers"; - } - if (args[1] > args[0]) { - return "First number needs to be larger than the second" - } - const number = Math.round(Math.random() * +args[0] - 1) + 1; - message!.channel!.send("Number was generated! The number is: " + number); + run(_client, message, args, _guildData, _userData, _isSlashCommand) { + if (args[0] === void 0 || args[0] === `` || args[1] === void 0 || args[1] === ``) { + return "Please specify two numbers"; + } + if (!(IsSomething.isNumber(args[0])) || !(IsSomething.isNumber(args[1]))) { + return "Both parameters need to be numbers"; + } + if (args[1] > args[0]) { + return "First number needs to be larger than the second" + } + const number = Math.round(Math.random() * +args[0] - 1) + 1; + message!.channel!.send("Number was generated! The number is: " + number); - if (number === +(args[1])) { - return "Your number is correct!"; - } else - return "Your number is false!"; - } + if (number === +(args[1])) { + return "Your number is correct!"; + } else + return "Your number is false!"; + } } as Command; \ No newline at end of file diff --git a/commands/general/help.ts b/commands/general/help.ts index 899b18f..5e8d70f 100644 --- a/commands/general/help.ts +++ b/commands/general/help.ts @@ -7,85 +7,85 @@ const { StringUtil } = require("sussy-util"); const fs = require("fs"); module.exports = { - description: "Displays all commands / more information about one command", - aliases: ["h"], + description: "Displays all commands / more information about one command", + aliases: ["h"], - options: [ - { - name: "query", - description: "name of the command", - type: ApplicationCommandOptionType.String, - required: false, - } - ], + options: [ + { + name: "query", + description: "name of the command", + type: ApplicationCommandOptionType.String, + required: false, + } + ], - run(client, _message, args, _guildData, _userData, _isSlashCommand) { - const menu = new StringSelectMenuBuilder() - .setCustomId("help") - .setPlaceholder("Select a category"); - const component = new ActionRowBuilder(); - const commandName = args[0]; - const embed = new EmbedBuilder() - .setTimestamp(new Date()) - .setTitle("Help panel") - // @ts-expect-error - .setFooter(client.config.embedFooter(client)); + run(client, _message, args, _guildData, _userData, _isSlashCommand) { + const menu = new StringSelectMenuBuilder() + .setCustomId("help") + .setPlaceholder("Select a category"); + const component = new ActionRowBuilder(); + const commandName = args[0]; + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Help panel") + // @ts-expect-error + .setFooter(client.config.embedFooter(client)); - if (commandName === void 0 || commandName.length === 0) { - embed - .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); + if (commandName === void 0 || commandName.length === 0) { + embed + .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); - fs.readdirSync(`${__dirname}/../`).forEach((d: any) => { - embed.addFields({ - name: StringUtil.capitalize(d), - value: "Type `" + client.config.prefix + "help " + d + "` to see more information", - }) - menu.addOptions({ label: StringUtil.capitalize(d), value: d }); - });; - } else { - const cmd = client.commands.get(`command:${commandName}`) || - client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + fs.readdirSync(`${__dirname}/../`).forEach((d: any) => { + embed.addFields({ + name: StringUtil.capitalize(d), + value: "Type `" + client.config.prefix + "help " + d + "` to see more information", + }) + menu.addOptions({ label: StringUtil.capitalize(d), value: d }); + });; + } else { + const cmd = client.commands.get(`command:${commandName}`) || + client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); - if (cmd === void 0) { - return "No command found for: `" + commandName + "`"; - } + if (cmd === void 0) { + return "No command found for: `" + commandName + "`"; + } - // TODO: Add more information + // TODO: Add more information - embed.addFields( - { - name: "Name", - value: cmd.name, - inline: true - }, - { - name: "Description", - value: cmd.description, - inline: true - }, - { - name: "Category", - value: cmd.category, - inline: true - }, - { - name: cmd.aliases?.length! > 1 ? "Aliases" : "Alias", - value: cmd.aliases?.length! > 0 ? cmd.aliases!.join(", ") : "None", - inline: true - }, - { - name: "Cooldown", - // @ts-expect-error - value: cmd.commandOptions?.defaultReturn?.cooldown ? `${cmd.cooldown}seconds` : "None", - inline: true - } - ); - } - if (menu.options.length > 0) { - component.addComponents(menu); - return { embeds: [embed], components: [component] }; - } else { - return { embeds: [embed] }; - } - } + embed.addFields( + { + name: "Name", + value: cmd.name, + inline: true + }, + { + name: "Description", + value: cmd.description, + inline: true + }, + { + name: "Category", + value: cmd.category, + inline: true + }, + { + name: cmd.aliases?.length! > 1 ? "Aliases" : "Alias", + value: cmd.aliases?.length! > 0 ? cmd.aliases!.join(", ") : "None", + inline: true + }, + { + name: "Cooldown", + // @ts-expect-error + value: cmd.commandOptions?.defaultReturn?.cooldown ? `${cmd.cooldown}seconds` : "None", + inline: true + } + ); + } + if (menu.options.length > 0) { + component.addComponents(menu); + return { embeds: [embed], components: [component] }; + } else { + return { embeds: [embed] }; + } + } } as Command; diff --git a/commands/general/info.ts b/commands/general/info.ts index 40b70c4..5af07a4 100644 --- a/commands/general/info.ts +++ b/commands/general/info.ts @@ -5,30 +5,30 @@ const { EmbedBuilder, version: discordjsVersion, Colors } = require("discord.js" const ms = require("@parade/pretty-ms"); module.exports = { - description: "Displays information about the bot.", + description: "Displays information about the bot.", - run(client, _message, _args, _guildData, _userData, _isSlashCommand) { - return { - embeds: [new EmbedBuilder() - .setColor(Colors.Red) - .setTitle(`${client.user.username} v${require("../../package.json")["version"]}`) - .setThumbnail(client.user.displayAvatarURL()) - .setURL("https://github.com/plastik-flasche/SUS-Bot") - .addFields( - { name: "Uptime", value: `${ms(client.uptime)}`, inline: true }, - { name: "WebSocket Ping", value: `${client.ws.ping}ms`, inline: true }, - { name: "Discord.js", value: `${discordjsVersion}`, inline: true }, - { name: "Guild Count", value: `${client.guilds.cache.size} guilds`, inline: true }, - { name: "User Count", value: `${client.users.cache.size} users`, inline: true }, - { name: "Commands", value: `${client.commands.filter(e => e.name!.startsWith("command:") && !e.ignore).size} commands`, inline: true }, - { name: "Memory", value: `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB RSS\n${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB Heap`, inline: true }, - { name: "Cached Data", value: `${client.users.cache.size} users\n${client.emojis.cache.size} emojis`, inline: true }, - { name: "Node", value: `${process.version} on ${process.platform} ${process.arch}`, inline: true } - ) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)) - .setTimestamp(new Date()) - ] - }; - } + run(client, _message, _args, _guildData, _userData, _isSlashCommand) { + return { + embeds: [new EmbedBuilder() + .setColor(Colors.Red) + .setTitle(`${client.user.username} v${require("../../package.json")["version"]}`) + .setThumbnail(client.user.displayAvatarURL()) + .setURL("https://github.com/plastik-flasche/SUS-Bot") + .addFields( + { name: "Uptime", value: `${ms(client.uptime)}`, inline: true }, + { name: "WebSocket Ping", value: `${client.ws.ping}ms`, inline: true }, + { name: "Discord.js", value: `${discordjsVersion}`, inline: true }, + { name: "Guild Count", value: `${client.guilds.cache.size} guilds`, inline: true }, + { name: "User Count", value: `${client.users.cache.size} users`, inline: true }, + { name: "Commands", value: `${client.commands.filter(e => e.name!.startsWith("command:") && !e.ignore).size} commands`, inline: true }, + { name: "Memory", value: `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB RSS\n${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB Heap`, inline: true }, + { name: "Cached Data", value: `${client.users.cache.size} users\n${client.emojis.cache.size} emojis`, inline: true }, + { name: "Node", value: `${process.version} on ${process.platform} ${process.arch}`, inline: true } + ) + // @ts-expect-error + .setFooter(client.config.embedFooter(client)) + .setTimestamp(new Date()) + ] + }; + } } as Command; \ No newline at end of file diff --git a/commands/general/invite.ts b/commands/general/invite.ts index e6105fa..51d86d7 100644 --- a/commands/general/invite.ts +++ b/commands/general/invite.ts @@ -1,14 +1,14 @@ import { Command } from "../../types/command"; module.exports = { - description: "Sends the invite link of the server", - commandOptions: { - guildOnly: true, - }, + description: "Sends the invite link of the server", + commandOptions: { + guildOnly: true, + }, - async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error // It can't even get to this point if it's not a guild - const invite = await message.channel!.createInvite({ unique: true, temporary: true }); - return "https://discord.gg/" + invite.code; - } + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error // It can't even get to this point if it's not a guild + const invite = await message.channel!.createInvite({ unique: true, temporary: true }); + return "https://discord.gg/" + invite.code; + } } as Command; diff --git a/commands/general/inviteBot.ts b/commands/general/inviteBot.ts index 7d8b441..a043f7e 100644 --- a/commands/general/inviteBot.ts +++ b/commands/general/inviteBot.ts @@ -2,9 +2,9 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; module.exports = { - description: "Sends the invite link of the bot", + description: "Sends the invite link of the bot", - async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { - return { content: "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands" }; - } + async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { + return { content: "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands" }; + } } as Command; diff --git a/commands/general/serverinfo.ts b/commands/general/serverinfo.ts index 42d0eef..5efd158 100644 --- a/commands/general/serverinfo.ts +++ b/commands/general/serverinfo.ts @@ -3,19 +3,19 @@ import { Command } from "../../types/command"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { - description: "Shows information about the server", + description: "Shows information about the server", - async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { - const sEmbed = new EmbedBuilder() - .setColor(Colors.Red) - .setTitle("Server Info") - .setThumbnail(message.guild!.iconURL()) - .setAuthor({ name: `${message.guild!.name} Info`, iconUrl: message.guild!.iconURL() }) - .addFields({ name: "***Guild Name:***", value: `${message.guild!.name}`, inline: true }, - { name: "***Guild Owner:***", value: `<@!${message.guild!.ownerId}>`, inline: true }, - { name: "***Member Count:***", value: `${message.guild!.memberCount}`, inline: true }) - .setTimestamp(new Date()); + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { + const sEmbed = new EmbedBuilder() + .setColor(Colors.Red) + .setTitle("Server Info") + .setThumbnail(message.guild!.iconURL()) + .setAuthor({ name: `${message.guild!.name} Info`, iconUrl: message.guild!.iconURL() }) + .addFields({ name: "***Guild Name:***", value: `${message.guild!.name}`, inline: true }, + { name: "***Guild Owner:***", value: `<@!${message.guild!.ownerId}>`, inline: true }, + { name: "***Member Count:***", value: `${message.guild!.memberCount}`, inline: true }) + .setTimestamp(new Date()); - return { embeds: [sEmbed] }; - } + return { embeds: [sEmbed] }; + } } as Command; diff --git a/commands/general/userinfo.ts b/commands/general/userinfo.ts index c754c18..5ffb5aa 100644 --- a/commands/general/userinfo.ts +++ b/commands/general/userinfo.ts @@ -3,31 +3,31 @@ import { Command } from "../../types/command"; const { EmbedBuilder, Colors } = require('discord.js'); module.exports = { - description: "Displays information about the current user.", + description: "Displays information about the current user.", - run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error // yes, it does exist! - const user = message.mentions!.users.first() || client.users.cache.get(args[0]) || message.author; + run(client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error // yes, it does exist! + const user = message.mentions!.users.first() || client.users.cache.get(args[0]) || message.author; - return { - embeds: [new EmbedBuilder() - .setTitle("**Userinfo**") - .setColor(Colors.Red) - .setThumbnail(user.displayAvatarURL()) - .addFields( - { name: "Username", value: user.username, inline: true }, - { name: "ID", value: user.id, inline: true }, - { name: "Discriminator", value: user.discriminator, inline: true }, - { name: "Bot", value: `${user.bot ? "Yes" : "No"}`, inline: true }, - { name: "Verified", value: user.verified ? "Yes" : "No", inline: true }, - { name: "Created", value: user.createdAt.toDateString(), inline: true }, - // @ts-expect-error // WTF is this error? - { name: "Joined", value: new Date(message.guild.members.cache.get(user.id)!.joinedTimestamp).toDateString(), inline: true }, - ) - .setTimestamp(new Date()) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)) - ] - }; - } + return { + embeds: [new EmbedBuilder() + .setTitle("**Userinfo**") + .setColor(Colors.Red) + .setThumbnail(user.displayAvatarURL()) + .addFields( + { name: "Username", value: user.username, inline: true }, + { name: "ID", value: user.id, inline: true }, + { name: "Discriminator", value: user.discriminator, inline: true }, + { name: "Bot", value: `${user.bot ? "Yes" : "No"}`, inline: true }, + { name: "Verified", value: user.verified ? "Yes" : "No", inline: true }, + { name: "Created", value: user.createdAt.toDateString(), inline: true }, + // @ts-expect-error // WTF is this error? + { name: "Joined", value: new Date(message.guild.members.cache.get(user.id)!.joinedTimestamp).toDateString(), inline: true }, + ) + .setTimestamp(new Date()) + // @ts-expect-error + .setFooter(client.config.embedFooter(client)) + ] + }; + } } as Command; \ No newline at end of file diff --git a/commands/moderation/clear.ts b/commands/moderation/clear.ts index df80d9e..d351df9 100644 --- a/commands/moderation/clear.ts +++ b/commands/moderation/clear.ts @@ -4,86 +4,86 @@ import { ApplicationCommandOptionType, CommandInteraction, Message } from "disco import permissionStrings from "../../enums/permissionStrings"; module.exports = { - description: "Clears the last n messages", + description: "Clears the last n messages", - options: [ - { - name: "query", - type: ApplicationCommandOptionType.Integer, - description: "amount of messages to clear", - required: true - } - ], + options: [ + { + name: "query", + type: ApplicationCommandOptionType.Integer, + description: "amount of messages to clear", + required: true + } + ], - default_member_permissions: permissionStrings.ManageMessages, + default_member_permissions: permissionStrings.ManageMessages, - async run(_client, message, args, _guildData, _userData, isSlashCommand) { - const amount = parseInt(args[0]); + async run(_client, message, args, _guildData, _userData, isSlashCommand) { + const amount = parseInt(args[0]); - if (args[0] === "all") { - clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { - if (isSlashCommand) - // @ts-expect-error // look at the FIXME below - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - else - message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - }).catch((err: string) => { - if (isSlashCommand) - // @ts-expect-error // look at the FIXME below - message.followUp(err); - else - message.channel!.send(err); - }); + if (args[0] === "all") { + clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME below + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch((err: string) => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME below + message.followUp(err); + else + message.channel!.send(err); + }); - return null; - } else if (isNaN(amount)) return "Please provide a number as the first argument."; + return null; + } else if (isNaN(amount)) return "Please provide a number as the first argument."; - if (amount <= 0) return "Number must be at least 1."; + if (amount <= 0) return "Number must be at least 1."; - clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { - // FIXME: isSlashCommand is kinda unnecessary here when working with TypeScript cause we can check if message is a CommandInteraction - if (isSlashCommand) - // @ts-expect-error // look at the FIXME above - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - else - message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); - }).catch(err => { - if (isSlashCommand) - // @ts-expect-error // look at the FIXME above - message.followUp(err); - else - message.channel!.send(err); - }); + clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { + // FIXME: isSlashCommand is kinda unnecessary here when working with TypeScript cause we can check if message is a CommandInteraction + if (isSlashCommand) + // @ts-expect-error // look at the FIXME above + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + else + message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + }).catch(err => { + if (isSlashCommand) + // @ts-expect-error // look at the FIXME above + message.followUp(err); + else + message.channel!.send(err); + }); - return null; - } + return null; + } } as Command; function clearMessages(message: Message | CommandInteraction, amount: number, isSlashCommand = false) { - return new Promise(async (resolve, reject) => { - let deletedMessagesCount = isSlashCommand ? 0 : -1; - while (deletedMessagesCount < amount) { - const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); - // @ts-expect-error // I just can't be bothered to fix this - const deletedMessages = await message.channel!.bulkDelete(deleteThisTime, true) - .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === void 0 || deletedMessages.size === 0) break; - deletedMessagesCount += deletedMessages.size; - } - resolve(deletedMessagesCount); - }); + return new Promise(async (resolve, reject) => { + let deletedMessagesCount = isSlashCommand ? 0 : -1; + while (deletedMessagesCount < amount) { + const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); + // @ts-expect-error // I just can't be bothered to fix this + const deletedMessages = await message.channel!.bulkDelete(deleteThisTime, true) + .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === void 0 || deletedMessages.size === 0) break; + deletedMessagesCount += deletedMessages.size; + } + resolve(deletedMessagesCount); + }); } function clearAllMessages(message: Message | CommandInteraction, isSlashCommand = false) { - return new Promise(async (resolve, reject) => { - let deletedMessagesCount = isSlashCommand ? 0 : -1; - while (true) { - // @ts-expect-error // I just can't be bothered to fix this - const deletedMessages = await message.channel!.bulkDelete(100, true) - .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === void 0 || deletedMessages.size === 0) break; - deletedMessagesCount += deletedMessages.size; - } - resolve(deletedMessagesCount); - }); + return new Promise(async (resolve, reject) => { + let deletedMessagesCount = isSlashCommand ? 0 : -1; + while (true) { + // @ts-expect-error // I just can't be bothered to fix this + const deletedMessages = await message.channel!.bulkDelete(100, true) + .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === void 0 || deletedMessages.size === 0) break; + deletedMessagesCount += deletedMessages.size; + } + resolve(deletedMessagesCount); + }); } \ No newline at end of file diff --git a/commands/moderation/lock.ts b/commands/moderation/lock.ts index 3a229f8..d225b77 100644 --- a/commands/moderation/lock.ts +++ b/commands/moderation/lock.ts @@ -6,38 +6,38 @@ import permissionStrings from "../../enums/permissionStrings"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { - description: "Locks a channel", - aliases: ["lockdown"], - - options: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to lock", - required: true - } - ], - - default_member_permissions: permissionStrings.ManageChannels, - - run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - channel ||= message.channel; - - if (!channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) - return "Channel is already locked"; - - channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: false }); - - const embed = new EmbedBuilder() - .setTitle("Channel Updates") - .setDescription(`<#${channel.id}> in now locked!`) - .setColor(Colors.Red) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)) - .setTimestamp(new Date()) - - return { embeds: [embed] }; - } + description: "Locks a channel", + aliases: ["lockdown"], + + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to lock", + required: true + } + ], + + default_member_permissions: permissionStrings.ManageChannels, + + run(client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + channel ||= message.channel; + + if (!channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) + return "Channel is already locked"; + + channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: false }); + + const embed = new EmbedBuilder() + .setTitle("Channel Updates") + .setDescription(`<#${channel.id}> in now locked!`) + .setColor(Colors.Red) + // @ts-expect-error + .setFooter(client.config.embedFooter(client)) + .setTimestamp(new Date()) + + return { embeds: [embed] }; + } } as Command; diff --git a/commands/moderation/nickname.ts b/commands/moderation/nickname.ts index 0830d77..8edb5a0 100644 --- a/commands/moderation/nickname.ts +++ b/commands/moderation/nickname.ts @@ -4,44 +4,44 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; module.exports = { - aliases: ["nick"], - description: "Nicks a user", + aliases: ["nick"], + description: "Nicks a user", - options: [ - { - name: "user", - type: ApplicationCommandOptionType.User, - description: "user you want to change the nickname of", - required: true, - }, - { - name: "nickname", - type: ApplicationCommandOptionType.String, - description: "nickname to change to", - required: true, - } - ], + options: [ + { + name: "user", + type: ApplicationCommandOptionType.User, + description: "user you want to change the nickname of", + required: true, + }, + { + name: "nickname", + type: ApplicationCommandOptionType.String, + description: "nickname to change to", + required: true, + } + ], - default_member_permissions: permissionStrings.ManageNicknames, + default_member_permissions: permissionStrings.ManageNicknames, - async run(_client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); - let nickName; - if (mentionedMember === void 0) { - nickName = args.slice(0).join(" "); - mentionedMember = message.member; - } - else nickName = args.slice(1).join(" "); + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); + let nickName; + if (mentionedMember === void 0) { + nickName = args.slice(0).join(" "); + mentionedMember = message.member; + } + else nickName = args.slice(1).join(" "); - if (nickName === void 0) return "Please provide a nickname for me to change this users nickname"; + if (nickName === void 0) return "Please provide a nickname for me to change this users nickname"; - try { - const username = mentionedMember.nickname || mentionedMember.user.username; - await mentionedMember.setNickname(nickName); - return `Set nickname of ${username} to ${nickName}.`; - } catch (err) { - return `I do not have the required permissions to to set ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; - } - } + try { + const username = mentionedMember.nickname || mentionedMember.user.username; + await mentionedMember.setNickname(nickName); + return `Set nickname of ${username} to ${nickName}.`; + } catch (err) { + return `I do not have the required permissions to to set ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; + } + } } as Command; diff --git a/commands/moderation/prepare.ts b/commands/moderation/prepare.ts index f767fa2..92699f7 100644 --- a/commands/moderation/prepare.ts +++ b/commands/moderation/prepare.ts @@ -5,32 +5,32 @@ import { CommandInteraction, Message } from "discord.js"; const { EmbedBuilder } = require("discord.js"); const registering = (client: Client, message: CommandInteraction | Message) => { - // @ts-expect-error - if (!message.member!.permissions.has("ADMINISTRATOR")) return new EmbedBuilder() - .setTitle("Failed to create slash-commands") - .setDescription("You do not have permissions to create slash-commands"); + // @ts-expect-error + if (!message.member!.permissions.has("ADMINISTRATOR")) return new EmbedBuilder() + .setTitle("Failed to create slash-commands") + .setDescription("You do not have permissions to create slash-commands"); - const embed = new EmbedBuilder() - .setTitle("Success") + const embed = new EmbedBuilder() + .setTitle("Success") - client.commands.forEach((command: Command) => { - if (command.name === "prepare") return; - // @ts-expect-error // cause name can't be undefined, look at index.ts - message.guild!.commands?.create(command).catch((error: Error) => { - return new EmbedBuilder() - .setTitle("Failed to create slash-commands") - .setDescription(error.toString()); - }); - }); + client.commands.forEach((command: Command) => { + if (command.name === "prepare") return; + // @ts-expect-error // cause name can't be undefined, look at index.ts + message.guild!.commands?.create(command).catch((error: Error) => { + return new EmbedBuilder() + .setTitle("Failed to create slash-commands") + .setDescription(error.toString()); + }); + }); - return embed; + return embed; } module.exports = { - description: "Creates slash commands in server", + description: "Creates slash commands in server", - async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - const embed = registering(client, message); - return { embeds: [embed] }; - } + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { + const embed = registering(client, message); + return { embeds: [embed] }; + } } as Command; diff --git a/commands/moderation/remove-nickname.ts b/commands/moderation/remove-nickname.ts index 1c6e27b..81f1eb8 100644 --- a/commands/moderation/remove-nickname.ts +++ b/commands/moderation/remove-nickname.ts @@ -4,31 +4,31 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; module.exports = { - aliases: ["remove-nick", "reset-nick", "reset-nickname", "un-nick", "un-nickname", "unnick", "unnickname", "removenick", "removenickname"], - description: "Removes a user\"s nickname", + aliases: ["remove-nick", "reset-nick", "reset-nickname", "un-nick", "un-nickname", "unnick", "unnickname", "removenick", "removenickname"], + description: "Removes a user\"s nickname", - options: [ - { - name: "user", - type: ApplicationCommandOptionType.User, - description: "User you want to change the nickname of", - required: true, - } - ], + options: [ + { + name: "user", + type: ApplicationCommandOptionType.User, + description: "User you want to change the nickname of", + required: true, + } + ], - default_member_permissions: permissionStrings.ManageNicknames, + default_member_permissions: permissionStrings.ManageNicknames, - async run(_client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); - mentionedMember ||= message.member; + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); + mentionedMember ||= message.member; - try { - const username = mentionedMember.nickname || mentionedMember.user.username; - await mentionedMember.setNickname(null); - return `Reset nickname of ${username}.`; - } catch (err) { - return `I do not have the required permissions to to reset ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; - } - } + try { + const username = mentionedMember.nickname || mentionedMember.user.username; + await mentionedMember.setNickname(null); + return `Reset nickname of ${username}.`; + } catch (err) { + return `I do not have the required permissions to to reset ${mentionedMember.nickname || mentionedMember.user.username}'s username.`; + } + } } as Command; diff --git a/commands/moderation/set-counter-channel.ts b/commands/moderation/set-counter-channel.ts index 74410d7..c133fa3 100644 --- a/commands/moderation/set-counter-channel.ts +++ b/commands/moderation/set-counter-channel.ts @@ -5,32 +5,32 @@ import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; module.exports = { - ignore: true, //TODO: Needs fix ASAP - description: "Sets the counter channel", - aliases: ["scc"], + ignore: true, //TODO: Needs fix ASAP + description: "Sets the counter channel", + aliases: ["scc"], - options: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to set as counter channel.", - required: true - } - ], + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to set as counter channel.", + required: true + } + ], - default_member_permissions: permissionStrings.ManageChannels, + default_member_permissions: permissionStrings.ManageChannels, - async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === void 0) channel = message.channel; - const current = guildData.channels; - current.counter = channel.id; + async run(_client, message, args, guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + if (channel === void 0) channel = message.channel; + const current = guildData.channels; + current.counter = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return `Set counter channel to ${channel.toString()}`; - } + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return `Set counter channel to ${channel.toString()}`; + } } as Command; diff --git a/commands/moderation/set-goodbye-channel.ts b/commands/moderation/set-goodbye-channel.ts index 4ace7bf..2eb0d43 100644 --- a/commands/moderation/set-goodbye-channel.ts +++ b/commands/moderation/set-goodbye-channel.ts @@ -5,32 +5,32 @@ import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; module.exports = { - ignore: true, //TODO: Needs fix ASAP - description: "Sets the goodbye channel", - aliases: ["sgc"], + ignore: true, //TODO: Needs fix ASAP + description: "Sets the goodbye channel", + aliases: ["sgc"], - options: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to set as goodbye channel.", - required: true - } - ], + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to set as goodbye channel.", + required: true + } + ], - default_member_permissions: permissionStrings.ManageChannels, + default_member_permissions: permissionStrings.ManageChannels, - async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === undefined) channel = message.channel; - const current = guildData.channels; - current.goodbye = channel.id; + async run(_client, message, args, guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + if (channel === undefined) channel = message.channel; + const current = guildData.channels; + current.goodbye = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return `Set goodbye channel to ${channel.toString()}`; - } + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return `Set goodbye channel to ${channel.toString()}`; + } } as Command; diff --git a/commands/moderation/set-welcome-channel.ts b/commands/moderation/set-welcome-channel.ts index 44649fe..51a2936 100644 --- a/commands/moderation/set-welcome-channel.ts +++ b/commands/moderation/set-welcome-channel.ts @@ -5,32 +5,32 @@ import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; module.exports = { - ignore: true, //TODO: Needs fix ASAP - description: "Sets the welcome channel", - aliases: ["swc"], + ignore: true, //TODO: Needs fix ASAP + description: "Sets the welcome channel", + aliases: ["swc"], - options: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to set as welcome channel.", - required: true - } - ], + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to set as welcome channel.", + required: true + } + ], - default_member_permissions: permissionStrings.ManageChannels, + default_member_permissions: permissionStrings.ManageChannels, - async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - channel ||= message.channel; - const current = guildData.channels; - current.welcome = channel.id; + async run(_client, message, args, guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + channel ||= message.channel; + const current = guildData.channels; + current.welcome = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { - if (err) console.error(err); - if (!data) return "Error: User not found."; - }); - return `Set welcome channel to ${channel.toString()}`; - } + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + return `Set welcome channel to ${channel.toString()}`; + } } as Command; diff --git a/commands/moderation/slowmode.ts b/commands/moderation/slowmode.ts index 87e81f9..7eff7cc 100644 --- a/commands/moderation/slowmode.ts +++ b/commands/moderation/slowmode.ts @@ -4,41 +4,41 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; module.exports = { - description: "Sets the slowmode of the current channel", - - option: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to set the slowmode of", - required: true - }, - { - name: "timeout", - type: ApplicationCommandOptionType.Integer, - description: "The timeout you want in seconds", - required: false - } - ], - - default_member_permissions: permissionStrings.ManageChannels, - - run(_client, message, args, _guildData, _userData, _isSlashCommand) { - let rate; - - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === void 0) { - channel = message.channel; - rate = args[0]; - } else rate = args[1]; - - if (typeof rate !== "number" || rate === 0) { - channel.setRateLimitPerUser(0); - return `The slowmode of ${channel.toString()} was removed.`; - } - - channel.setRateLimitPerUser(+rate); - return `The slowmode of ${channel.toString()} was set to ${rate} seconds.`; - } + description: "Sets the slowmode of the current channel", + + option: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to set the slowmode of", + required: true + }, + { + name: "timeout", + type: ApplicationCommandOptionType.Integer, + description: "The timeout you want in seconds", + required: false + } + ], + + default_member_permissions: permissionStrings.ManageChannels, + + run(_client, message, args, _guildData, _userData, _isSlashCommand) { + let rate; + + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + if (channel === void 0) { + channel = message.channel; + rate = args[0]; + } else rate = args[1]; + + if (typeof rate !== "number" || rate === 0) { + channel.setRateLimitPerUser(0); + return `The slowmode of ${channel.toString()} was removed.`; + } + + channel.setRateLimitPerUser(+rate); + return `The slowmode of ${channel.toString()} was set to ${rate} seconds.`; + } } as Command; diff --git a/commands/moderation/tempban.ts b/commands/moderation/tempban.ts index 89495fc..9f39f40 100644 --- a/commands/moderation/tempban.ts +++ b/commands/moderation/tempban.ts @@ -5,29 +5,29 @@ import permissionStrings from "../../enums/permissionStrings"; // TODO: write temp ban command module.exports = { - ignore: true, - description: "", - aliases: ["tempban", "temp-ban"], + ignore: true, + description: "", + aliases: ["tempban", "temp-ban"], - options: [ - { - name: "user", - type: ApplicationCommandOptionType.User, - description: "User you want to tempban", - required: true, - }, - { - name: "days", - type: ApplicationCommandOptionType.Integer, - description: "The amount of days you want to ban the user", - required: true - } - ], + options: [ + { + name: "user", + type: ApplicationCommandOptionType.User, + description: "User you want to tempban", + required: true, + }, + { + name: "days", + type: ApplicationCommandOptionType.Integer, + description: "The amount of days you want to ban the user", + required: true + } + ], - default_member_permissions: permissionStrings.BanMembers, + default_member_permissions: permissionStrings.BanMembers, - run(client, message, args, guildData, userData, isSlashCommand) { + run(client, message, args, guildData, userData, isSlashCommand) { - } + } } as Command; diff --git a/commands/moderation/unban.ts b/commands/moderation/unban.ts index 67e0ed7..1a8b692 100644 --- a/commands/moderation/unban.ts +++ b/commands/moderation/unban.ts @@ -4,35 +4,35 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; module.exports = { - ignore: true, - description: "Unbans a user", - - options: [ - { - name: "user", - type: ApplicationCommandOptionType.User, - description: "User you want to unban", - required: true, - } - ], - - default_member_permissions: permissionStrings.BanMembers, - - async run(_client, message, args, _guildData, _userData, _isSlashCommand) { - if (args[0] === void 0) - return "Please Give Me Member ID That You Want To Unban!"; - - const bans = await message.guild!.bans.fetch(); - const member = bans.find(b => b.user.username.toLowerCase() === args[0].toLocaleLowerCase()) || bans.get(args[0]) || bans.find(bm => bm.user.tag.toLowerCase() === args[0].toLocaleLowerCase()); - - if (member === void 0) - return "Please Give Valid Member ID Or Member Is Not Banned!"; - - try { - await message.guild!.members.unban(member.user.id, args[1] || "No Reason Provided!"); - return `Unbanned <@!${args[0]}>. With reason: ${args[1] || "No Reason Provided!"}`; - } catch (error) { - return "I Can't Unban That Member Maybe Member Is Not Banned Or Some Error!"; - } - } + ignore: true, + description: "Unbans a user", + + options: [ + { + name: "user", + type: ApplicationCommandOptionType.User, + description: "User you want to unban", + required: true, + } + ], + + default_member_permissions: permissionStrings.BanMembers, + + async run(_client, message, args, _guildData, _userData, _isSlashCommand) { + if (args[0] === void 0) + return "Please Give Me Member ID That You Want To Unban!"; + + const bans = await message.guild!.bans.fetch(); + const member = bans.find(b => b.user.username.toLowerCase() === args[0].toLocaleLowerCase()) || bans.get(args[0]) || bans.find(bm => bm.user.tag.toLowerCase() === args[0].toLocaleLowerCase()); + + if (member === void 0) + return "Please Give Valid Member ID Or Member Is Not Banned!"; + + try { + await message.guild!.members.unban(member.user.id, args[1] || "No Reason Provided!"); + return `Unbanned <@!${args[0]}>. With reason: ${args[1] || "No Reason Provided!"}`; + } catch (error) { + return "I Can't Unban That Member Maybe Member Is Not Banned Or Some Error!"; + } + } } as Command; diff --git a/commands/moderation/unlock.ts b/commands/moderation/unlock.ts index f5e6f64..c09c48e 100644 --- a/commands/moderation/unlock.ts +++ b/commands/moderation/unlock.ts @@ -6,38 +6,38 @@ import permissionStrings from "../../enums/permissionStrings"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { - description: "Unlocks a channel", - aliases: [], - - options: [ - { - name: "channel", - type: ApplicationCommandOptionType.Channel, - description: "The channel you want to unlock", - required: true - } - ], - - default_member_permissions: permissionStrings.ManageChannels, - - run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let channel = global.functions.getChannelFromMention(message.guild, args[0]); - channel ||= message.channel; - - if (channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) - return "Channel isn't locked"; - - channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: true }); - - const embed = new EmbedBuilder() - .setTitle("Channel Updates") - .setDescription(`<#${channel.id}> is now unlocked!`) - .setColor(Colors.Red) - // @ts-expect-error - .setFooter(client.config.embedFooter(client)) - .setTimestamp(new Date()) - - return { embeds: [embed] }; - } + description: "Unlocks a channel", + aliases: [], + + options: [ + { + name: "channel", + type: ApplicationCommandOptionType.Channel, + description: "The channel you want to unlock", + required: true + } + ], + + default_member_permissions: permissionStrings.ManageChannels, + + run(client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error + let channel = global.functions.getChannelFromMention(message.guild, args[0]); + channel ||= message.channel; + + if (channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) + return "Channel isn't locked"; + + channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: true }); + + const embed = new EmbedBuilder() + .setTitle("Channel Updates") + .setDescription(`<#${channel.id}> is now unlocked!`) + .setColor(Colors.Red) + // @ts-expect-error + .setFooter(client.config.embedFooter(client)) + .setTimestamp(new Date()) + + return { embeds: [embed] }; + } } as Command; diff --git a/commands/music/clearQueue.ts b/commands/music/clearQueue.ts index 38c8348..5829642 100644 --- a/commands/music/clearQueue.ts +++ b/commands/music/clearQueue.ts @@ -1,12 +1,12 @@ import { Command } from "../../types/command"; module.exports = { - description: "Clears the song queue.", - commandOptions: { - connectedToSameVC: true - }, + description: "Clears the song queue.", + commandOptions: { + connectedToSameVC: true + }, - run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.clearQueue(message); - } + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.clearQueue(message); + } } as Command; diff --git a/commands/music/loop.ts b/commands/music/loop.ts index 9a503ca..601a61c 100644 --- a/commands/music/loop.ts +++ b/commands/music/loop.ts @@ -1,12 +1,12 @@ import { Command } from "../../types/command"; module.exports = { - description: "Loops the current queue.", - aliases: ["repeat"], - commandOptions: { - connectedToSameVC: true - }, - run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.toggleLoop(message); - }, + description: "Loops the current queue.", + aliases: ["repeat"], + commandOptions: { + connectedToSameVC: true + }, + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.toggleLoop(message); + }, } as Command; diff --git a/commands/music/nowPlaying.ts b/commands/music/nowPlaying.ts index 1423f82..1b5aa76 100644 --- a/commands/music/nowPlaying.ts +++ b/commands/music/nowPlaying.ts @@ -1,23 +1,23 @@ import { Command } from "../../types/command"; module.exports = { - description: "Shows the current song", - aliases: ["current"], - commandOptions: { - connectedToSameVC: true - }, + description: "Shows the current song", + aliases: ["current"], + commandOptions: { + connectedToSameVC: true + }, - async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - if (client.player.getQueue(message.guild!.id) === void 0) { - return "There is no queue"; - } + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { + if (client.player.getQueue(message.guild!.id) === void 0) { + return "There is no queue"; + } - const current = client.player.getCurrent(message.guild!.id); + const current = client.player.getCurrent(message.guild!.id); - if (current === void 0) { - return "Currently not playing anything"; - } + if (current === void 0) { + return "Currently not playing anything"; + } - return `Now Playing: **${current.title}**\n`; - } + return `Now Playing: **${current.title}**\n`; + } } as Command; diff --git a/commands/music/pause.ts b/commands/music/pause.ts index 2820570..8683db7 100644 --- a/commands/music/pause.ts +++ b/commands/music/pause.ts @@ -1,13 +1,13 @@ import { Command } from "../../types/command"; module.exports = { - aliases: [], - description: "Pauses the current song", - commandOptions: { - connectedToSameVC: true - }, + aliases: [], + description: "Pauses the current song", + commandOptions: { + connectedToSameVC: true + }, - run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.pause(message); - } + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.pause(message); + } } as Command; diff --git a/commands/music/play.ts b/commands/music/play.ts index d24155a..88fc3c2 100644 --- a/commands/music/play.ts +++ b/commands/music/play.ts @@ -2,22 +2,22 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; module.exports = { - description: "Adds a song to the queue", - aliases: ["p"], - connectedToVC: true, + description: "Adds a song to the queue", + aliases: ["p"], + connectedToVC: true, - options: [ - { - name: "query", - type: ApplicationCommandOptionType.String, - description: "Link/Name of track to play", - required: true - } - ], + options: [ + { + name: "query", + type: ApplicationCommandOptionType.String, + description: "Link/Name of track to play", + required: true + } + ], - async run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error // cause it's getting caught anyway - try { message.suppressEmbeds(true); } catch (e) { } - return client.player.addTrack(message, args); - } + async run(client, message, args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error // cause it's getting caught anyway + try { message.suppressEmbeds(true); } catch (e) { } + return client.player.addTrack(message, args); + } } as Command; diff --git a/commands/music/queue.ts b/commands/music/queue.ts index 00bda23..d3e7bfb 100644 --- a/commands/music/queue.ts +++ b/commands/music/queue.ts @@ -1,29 +1,29 @@ import { Command } from "../../types/command"; module.exports = { - description: "Shows the song queue", - aliases: ["q"], - commandOptions: { - connectedToSameVC: true - }, + description: "Shows the song queue", + aliases: ["q"], + commandOptions: { + connectedToSameVC: true + }, - async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - const playerInfo = client.player.getQueue(message.guild!.id); + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { + const playerInfo = client.player.getQueue(message.guild!.id); - if (playerInfo === void 0) { - return "There are no songs in the queue"; - } + if (playerInfo === void 0) { + return "There are no songs in the queue"; + } - let currentString = `Current: **${playerInfo.current.title}**\n`; - let queueString = ""; + let currentString = `Current: **${playerInfo.current.title}**\n`; + let queueString = ""; - for (let i = 0; i < Math.min(playerInfo.queue.length, 18); i++) { - const track = playerInfo.queue[i]; - queueString += `${i + 1}. **${track.title}**\n`; - } - if (playerInfo.queue.length > 18) - queueString += `And ${playerInfo.queue.length - 18} more...`; + for (let i = 0; i < Math.min(playerInfo.queue.length, 18); i++) { + const track = playerInfo.queue[i]; + queueString += `${i + 1}. **${track.title}**\n`; + } + if (playerInfo.queue.length > 18) + queueString += `And ${playerInfo.queue.length - 18} more...`; - return (currentString + queueString); - } + return (currentString + queueString); + } } as Command; diff --git a/commands/music/resume.ts b/commands/music/resume.ts index 10fba2d..09abc9b 100644 --- a/commands/music/resume.ts +++ b/commands/music/resume.ts @@ -1,13 +1,13 @@ import { Command } from "../../types/command"; module.exports = { - aliases: ["unpause"], - description: "Resumes playing", - commandOptions: { - connectedToSameVC: true - }, + aliases: ["unpause"], + description: "Resumes playing", + commandOptions: { + connectedToSameVC: true + }, - run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.resume(message); - } + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.resume(message); + } } as Command; diff --git a/commands/music/shuffle.ts b/commands/music/shuffle.ts index 2e273e6..ed541ff 100644 --- a/commands/music/shuffle.ts +++ b/commands/music/shuffle.ts @@ -1,13 +1,13 @@ import { Command } from "../../types/command"; module.exports = { - description: "Shuffles the queue", - aliases: ["mix"], - commandOptions: { - connectedToSameVC: true - }, + description: "Shuffles the queue", + aliases: ["mix"], + commandOptions: { + connectedToSameVC: true + }, - async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.shuffle(message); - } + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.shuffle(message); + } } as Command; diff --git a/commands/music/skip.ts b/commands/music/skip.ts index cb44f3e..ca916aa 100644 --- a/commands/music/skip.ts +++ b/commands/music/skip.ts @@ -1,13 +1,13 @@ import { Command } from "../../types/command"; module.exports = { - description: "Skips current track", - aliases: ["next"], - commandOptions: { - connectedToSameVC: true - }, + description: "Skips current track", + aliases: ["next"], + commandOptions: { + connectedToSameVC: true + }, - run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.skip(message); // call the skip function from the player - } + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.skip(message); // call the skip function from the player + } } as Command; diff --git a/commands/music/stop.ts b/commands/music/stop.ts index 74cdd78..5c18f03 100644 --- a/commands/music/stop.ts +++ b/commands/music/stop.ts @@ -1,13 +1,13 @@ import { Command } from "../../types/command"; module.exports = { - description: "Stops the music and clears the queue", - aliases: ["disconnect", "leave"], - commandOptions: { - connectedToSameVC: true - }, + description: "Stops the music and clears the queue", + aliases: ["disconnect", "leave"], + commandOptions: { + connectedToSameVC: true + }, - async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - return client.player.stop(message); - } + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { + return client.player.stop(message); + } } as Command; diff --git a/commands/music/troll.ts b/commands/music/troll.ts index ad7fd78..c0864d8 100644 --- a/commands/music/troll.ts +++ b/commands/music/troll.ts @@ -1,19 +1,19 @@ import { Command } from "../../types/command"; module.exports = { - ignore: true, - aliases: ["t"], - category: "Music", - description: "A wild troll appeared.", - connectedToVC: true, + ignore: true, + aliases: ["t"], + category: "Music", + description: "A wild troll appeared.", + connectedToVC: true, - run(client, message, _args, _guildData, _userData, isSlashCommand) { - // @ts-expect-error - if (!isSlashCommand) message.delete(); + run(client, message, _args, _guildData, _userData, isSlashCommand) { + // @ts-expect-error + if (!isSlashCommand) message.delete(); - // @ts-expect-error // Log the user using the command cause roteKlaue - console.log(`${message.author.username} used the troll command.`); - client.player.troll(message); - return null; - } + // @ts-expect-error // Log the user using the command cause roteKlaue + console.log(`${message.author.username} used the troll command.`); + client.player.troll(message); + return null; + } } as Command; diff --git a/commands/testcommands/ping.ts b/commands/testcommands/ping.ts index d32dff6..cc35fd7 100644 --- a/commands/testcommands/ping.ts +++ b/commands/testcommands/ping.ts @@ -5,43 +5,43 @@ import { Command } from "../../types/command"; const { EmbedBuilder, Colors } = require("discord.js"); const after = (client: Client, message: Message, sentMessage: Message, start: number, slash = false) => { - const EndDate = Date.now(); - const embed = new EmbedBuilder() - .setColor(Colors.Red) - .setTitle("Pong!") - .addFields({ name: "Message Latency", value: `${Math.floor(EndDate - start)}ms` }, - { name: "API Latency", value: `${Math.round(client.ws.ping)}ms` }) - .setTimestamp(new Date); + const EndDate = Date.now(); + const embed = new EmbedBuilder() + .setColor(Colors.Red) + .setTitle("Pong!") + .addFields({ name: "Message Latency", value: `${Math.floor(EndDate - start)}ms` }, + { name: "API Latency", value: `${Math.round(client.ws.ping)}ms` }) + .setTimestamp(new Date); - if (slash) { - // @ts-expect-error // it does exist, ig... - message.followUp({ embeds: [embed] }); - } else { - sentMessage.delete(); - return { embeds: [embed] }; - } + if (slash) { + // @ts-expect-error // it does exist, ig... + message.followUp({ embeds: [embed] }); + } else { + sentMessage.delete(); + return { embeds: [embed] }; + } } //TODO: I implemented returning null for a reason... So ig I should use it here module.exports = { - description: "Pings the bot and displays the latency of the bot and the latency of the api.", + description: "Pings the bot and displays the latency of the bot and the latency of the api.", - async run(client, message, _args, _guildData, _userData, isSlashCommand) { - const sendObj = { embeds: [new EmbedBuilder().setColor(Colors.Red).setDescription("Please Wait...")] }; - const StartDate = Date.now(); - if (isSlashCommand) { - // @ts-expect-error // I do think it exists but I just selected the wrong type bc I want to finish this as soon as possible // FIXME - await message.deferReply(); - // @ts-expect-error // same here - message.followUp(sendObj).then(msg => { - // @ts-expect-error // FIXME pls, this is pure agony - after(client, message, msg, StartDate, true); - }); - } else { - return message.channel!.send(sendObj) - // @ts-expect-error // FIXME pls, this is pure agony - .then((msg) => { return after(client, message, msg, StartDate) }); - } - } + async run(client, message, _args, _guildData, _userData, isSlashCommand) { + const sendObj = { embeds: [new EmbedBuilder().setColor(Colors.Red).setDescription("Please Wait...")] }; + const StartDate = Date.now(); + if (isSlashCommand) { + // @ts-expect-error // I do think it exists but I just selected the wrong type bc I want to finish this as soon as possible // FIXME + await message.deferReply(); + // @ts-expect-error // same here + message.followUp(sendObj).then(msg => { + // @ts-expect-error // FIXME pls, this is pure agony + after(client, message, msg, StartDate, true); + }); + } else { + return message.channel!.send(sendObj) + // @ts-expect-error // FIXME pls, this is pure agony + .then((msg) => { return after(client, message, msg, StartDate) }); + } + } } as Command; diff --git a/commands/testcommands/playtest.ts b/commands/testcommands/playtest.ts index 40026cf..707b5a8 100644 --- a/commands/testcommands/playtest.ts +++ b/commands/testcommands/playtest.ts @@ -1,65 +1,65 @@ import { Command } from "../../types/command"; module.exports = { - description: "Plays a random song from a list", - aliases: ["pt"], + description: "Plays a random song from a list", + aliases: ["pt"], - async run(client, message, _args, guildData, userData, isSlashCommand) { - const pickedSong = songList[Math.floor(Math.random() * songList.length)]; - return require("../music/play").run(client, message, [pickedSong], guildData, userData, isSlashCommand); - } + async run(client, message, _args, guildData, userData, isSlashCommand) { + const pickedSong = songList[Math.floor(Math.random() * songList.length)]; + return require("../music/play").run(client, message, [pickedSong], guildData, userData, isSlashCommand); + } } as Command; const songList = [ - "https://www.youtube.com/watch?v=52Gg9CqhbP8&list=RDMM&index=1", - "https://www.youtube.com/watch?v=NkRkuI0ZgX0&list=RDMM&index=2", - "https://www.youtube.com/watch?v=PcR8I-7oCnU&list=RDMM&index=3", - "https://www.youtube.com/watch?v=myiJB8SiIcU&list=RDMM&index=4", - "https://www.youtube.com/watch?v=H87GqJujcOk&list=RDMM&index=5", - "https://www.youtube.com/watch?v=EHyoAXILbA8&list=RDMM&index=6", - "https://www.youtube.com/watch?v=XRP9k9nlAfE&list=RDMM&index=7", - "https://www.youtube.com/watch?v=bXE6B6Usj6o&list=RDMM&index=8", - "https://www.youtube.com/watch?v=ZPqZyIKtW0Y&list=RDMM&index=9", - "https://www.youtube.com/watch?v=StYkb5kbM3o&list=RDMM&index=10", - "https://www.youtube.com/watch?v=7pA8hZqXWHY&list=RDMM&index=11", - "https://www.youtube.com/watch?v=3nlSDxvt6JU&list=RDMM&index=12", - "https://www.youtube.com/watch?v=jpw2ebhTSKs&list=RDMM&index=13", - "https://www.youtube.com/watch?v=IDmjQigyZiE&list=RDMM&index=14", - "https://www.youtube.com/watch?v=1RaKSRU60bw&list=RDMM&index=15", - "https://www.youtube.com/watch?v=74ekU02fxAQ&list=RDMM&index=16", - "https://www.youtube.com/watch?v=-kWFRyQ5VU8&list=RDMM&index=17", - "https://www.youtube.com/watch?v=On_ZA4RNfyU&list=RDMM&index=18", - "https://www.youtube.com/watch?v=DBXTRtm07RA&list=RDMM&index=19", - "https://www.youtube.com/watch?v=MaeRXppkzdA&list=RDMM&index=20", - "https://www.youtube.com/watch?v=PDJLvF1dUek&list=RDMM&index=21", - "https://www.youtube.com/watch?v=US3VTVDRbjE&list=RDMM&index=22", - "https://www.youtube.com/watch?v=VJr6jP4e14M&list=RDMM&index=23", - "https://www.youtube.com/watch?v=_Fxil2QY0wE&list=RDMM&index=24", - "https://www.youtube.com/watch?v=fripFSuqztY&list=RDMM&index=25", - "https://www.youtube.com/watch?v=9BoaOsvZmpw&list=RDMM&index=26", - "https://www.youtube.com/watch?v=BTthtlT80Rc&list=RDMM&index=27", - "https://www.youtube.com/watch?v=fBGSJ3sbivI&list=RDMM&index=28", - "https://www.youtube.com/watch?v=EKLWC93nvAU&list=RDMM&index=29", - "https://www.youtube.com/watch?v=9RHFFeQ2tu4&list=RDMM&index=30", - "https://www.youtube.com/watch?v=VRwD9JL2sO0&list=RDMM&index=31", - "https://www.youtube.com/watch?v=8UVNT4wvIGY&list=RDMM&index=32", - "https://www.youtube.com/watch?v=lXnw5hrc1bs&list=RDMM&index=33", - "https://www.youtube.com/watch?v=FtutLA63Cp8&list=RDMM&index=34", - "https://www.youtube.com/watch?v=bOsKlHMfqbE&list=RDMM&index=35", - "https://www.youtube.com/watch?v=zhIScvlFn2w&list=RDMM&index=36", - "https://www.youtube.com/watch?v=LX5ntwkUa48&list=RDMM&index=37", - "https://www.youtube.com/watch?v=UbQgXeY_zi4&list=RDMM&index=38", - "https://www.youtube.com/watch?v=XEDb8hrHiKw&list=RDMM&index=39", - "https://www.youtube.com/watch?v=gaFh71YwZ4Y&list=RDMM&index=40", - "https://www.youtube.com/watch?v=scGd4fmGrTE&list=RDMM&index=41", - "https://www.youtube.com/watch?v=FPjJW5iTFN0&list=RDMM&index=42", - "https://www.youtube.com/watch?v=JpxLaTsylBU&list=RDMM&index=43", - "https://www.youtube.com/watch?v=AlYdp8P1s6c&list=RDMM&index=44", - "https://www.youtube.com/watch?v=9B1M3IPVcXs&list=RDMM&index=45", - "https://www.youtube.com/watch?v=H4PZ7mju5QQ&list=RDMM&index=46", - "https://www.youtube.com/watch?v=9Zj0JOHJR-s&list=RDMM&index=47", - "https://www.youtube.com/watch?v=PZbkF-15ObM&list=RDMM&index=48", - "https://www.youtube.com/watch?v=7T2sjD4bJU8&list=RDMM&index=49", - "https://www.youtube.com/watch?v=yebo5ILBMC0&list=RDMM&index=50", - "https://www.youtube.com/watch?v=-N4jf6rtyuw&list=RDMM&index=51" + "https://www.youtube.com/watch?v=52Gg9CqhbP8&list=RDMM&index=1", + "https://www.youtube.com/watch?v=NkRkuI0ZgX0&list=RDMM&index=2", + "https://www.youtube.com/watch?v=PcR8I-7oCnU&list=RDMM&index=3", + "https://www.youtube.com/watch?v=myiJB8SiIcU&list=RDMM&index=4", + "https://www.youtube.com/watch?v=H87GqJujcOk&list=RDMM&index=5", + "https://www.youtube.com/watch?v=EHyoAXILbA8&list=RDMM&index=6", + "https://www.youtube.com/watch?v=XRP9k9nlAfE&list=RDMM&index=7", + "https://www.youtube.com/watch?v=bXE6B6Usj6o&list=RDMM&index=8", + "https://www.youtube.com/watch?v=ZPqZyIKtW0Y&list=RDMM&index=9", + "https://www.youtube.com/watch?v=StYkb5kbM3o&list=RDMM&index=10", + "https://www.youtube.com/watch?v=7pA8hZqXWHY&list=RDMM&index=11", + "https://www.youtube.com/watch?v=3nlSDxvt6JU&list=RDMM&index=12", + "https://www.youtube.com/watch?v=jpw2ebhTSKs&list=RDMM&index=13", + "https://www.youtube.com/watch?v=IDmjQigyZiE&list=RDMM&index=14", + "https://www.youtube.com/watch?v=1RaKSRU60bw&list=RDMM&index=15", + "https://www.youtube.com/watch?v=74ekU02fxAQ&list=RDMM&index=16", + "https://www.youtube.com/watch?v=-kWFRyQ5VU8&list=RDMM&index=17", + "https://www.youtube.com/watch?v=On_ZA4RNfyU&list=RDMM&index=18", + "https://www.youtube.com/watch?v=DBXTRtm07RA&list=RDMM&index=19", + "https://www.youtube.com/watch?v=MaeRXppkzdA&list=RDMM&index=20", + "https://www.youtube.com/watch?v=PDJLvF1dUek&list=RDMM&index=21", + "https://www.youtube.com/watch?v=US3VTVDRbjE&list=RDMM&index=22", + "https://www.youtube.com/watch?v=VJr6jP4e14M&list=RDMM&index=23", + "https://www.youtube.com/watch?v=_Fxil2QY0wE&list=RDMM&index=24", + "https://www.youtube.com/watch?v=fripFSuqztY&list=RDMM&index=25", + "https://www.youtube.com/watch?v=9BoaOsvZmpw&list=RDMM&index=26", + "https://www.youtube.com/watch?v=BTthtlT80Rc&list=RDMM&index=27", + "https://www.youtube.com/watch?v=fBGSJ3sbivI&list=RDMM&index=28", + "https://www.youtube.com/watch?v=EKLWC93nvAU&list=RDMM&index=29", + "https://www.youtube.com/watch?v=9RHFFeQ2tu4&list=RDMM&index=30", + "https://www.youtube.com/watch?v=VRwD9JL2sO0&list=RDMM&index=31", + "https://www.youtube.com/watch?v=8UVNT4wvIGY&list=RDMM&index=32", + "https://www.youtube.com/watch?v=lXnw5hrc1bs&list=RDMM&index=33", + "https://www.youtube.com/watch?v=FtutLA63Cp8&list=RDMM&index=34", + "https://www.youtube.com/watch?v=bOsKlHMfqbE&list=RDMM&index=35", + "https://www.youtube.com/watch?v=zhIScvlFn2w&list=RDMM&index=36", + "https://www.youtube.com/watch?v=LX5ntwkUa48&list=RDMM&index=37", + "https://www.youtube.com/watch?v=UbQgXeY_zi4&list=RDMM&index=38", + "https://www.youtube.com/watch?v=XEDb8hrHiKw&list=RDMM&index=39", + "https://www.youtube.com/watch?v=gaFh71YwZ4Y&list=RDMM&index=40", + "https://www.youtube.com/watch?v=scGd4fmGrTE&list=RDMM&index=41", + "https://www.youtube.com/watch?v=FPjJW5iTFN0&list=RDMM&index=42", + "https://www.youtube.com/watch?v=JpxLaTsylBU&list=RDMM&index=43", + "https://www.youtube.com/watch?v=AlYdp8P1s6c&list=RDMM&index=44", + "https://www.youtube.com/watch?v=9B1M3IPVcXs&list=RDMM&index=45", + "https://www.youtube.com/watch?v=H4PZ7mju5QQ&list=RDMM&index=46", + "https://www.youtube.com/watch?v=9Zj0JOHJR-s&list=RDMM&index=47", + "https://www.youtube.com/watch?v=PZbkF-15ObM&list=RDMM&index=48", + "https://www.youtube.com/watch?v=7T2sjD4bJU8&list=RDMM&index=49", + "https://www.youtube.com/watch?v=yebo5ILBMC0&list=RDMM&index=50", + "https://www.youtube.com/watch?v=-N4jf6rtyuw&list=RDMM&index=51" ] diff --git a/commands/testcommands/testbot.ts b/commands/testcommands/testbot.ts index 5ed983a..2d1cd4b 100644 --- a/commands/testcommands/testbot.ts +++ b/commands/testcommands/testbot.ts @@ -1,12 +1,12 @@ import { Command } from "../../types/command"; module.exports = { - ignore: true, - description: "Command for testing all the bot's features", + ignore: true, + description: "Command for testing all the bot's features", - async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error // FIXME pls, I think I selected the wrong type - message.deferReply({ ephemeral: true }); - return null; - } + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { + // @ts-expect-error // FIXME pls, I think I selected the wrong type + message.deferReply({ ephemeral: true }); + return null; + } } as Command; diff --git a/commands/testcommands/uptime.ts b/commands/testcommands/uptime.ts index 3e7448b..dc18efc 100644 --- a/commands/testcommands/uptime.ts +++ b/commands/testcommands/uptime.ts @@ -3,21 +3,21 @@ import { Command } from "../../types/command"; const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { - "description": "Shows the uptime of the bot", + "description": "Shows the uptime of the bot", - async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { - const days = Math.floor(client.uptime / 86400000); - const hours = Math.floor(client.uptime / 3600000) % 24; - const minutes = Math.floor(client.uptime / 60000) % 60; - const seconds = Math.floor(client.uptime / 1000) % 60; + async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { + const days = Math.floor(client.uptime / 86400000); + const hours = Math.floor(client.uptime / 3600000) % 24; + const minutes = Math.floor(client.uptime / 60000) % 60; + const seconds = Math.floor(client.uptime / 1000) % 60; - const uptime = new EmbedBuilder() - .setColor(Colors.Red) - .setDescription(` \`\📝\`\ | **__Uptime:__**`) - .addFields({ name: "**Tage:**", value: `${days}` }, - { name: "**Stunden:**", value: `${hours}` }, - { name: "**Minuten:**", value: `${minutes}` }, - { name: "**Sekunden:**", value: `${seconds}` }); - return { embeds: [uptime] }; - } + const uptime = new EmbedBuilder() + .setColor(Colors.Red) + .setDescription(` \`\📝\`\ | **__Uptime:__**`) + .addFields({ name: "**Tage:**", value: `${days}` }, + { name: "**Stunden:**", value: `${hours}` }, + { name: "**Minuten:**", value: `${minutes}` }, + { name: "**Sekunden:**", value: `${seconds}` }); + return { embeds: [uptime] }; + } } as Command; diff --git a/config.ts b/config.ts index 7e5c4f6..af695ea 100644 --- a/config.ts +++ b/config.ts @@ -10,8 +10,8 @@ module.exports.fetchData = require("./functions/fetchDataFromSave"); module.exports.authorsString = ""; const { authors } = require("./package.json"); authors.forEach((author: string, index: number) => { - if (index === authors.length - 1) module.exports.authorsString += `and ${author}`; - else module.exports.authorsString += `${author}, `; + if (index === authors.length - 1) module.exports.authorsString += `and ${author}`; + else module.exports.authorsString += `${author}, `; }); module.exports.authorsString = module.exports.authorsString.replace(/, and/, " and"); module.exports.version = require("./package.json")["version"]; diff --git a/enums/permissionBitField.ts b/enums/permissionBitField.ts index 4306fa5..bd472aa 100644 --- a/enums/permissionBitField.ts +++ b/enums/permissionBitField.ts @@ -1,43 +1,43 @@ export default { - CreateInstantInvite: 1n << 0n, - KickMembers: 1n << 1n, - BanMembers: 1n << 2n, - Administrator: 1n << 3n, - ManageChannels: 1n << 4n, - ManageGuild: 1n << 5n, - AddReactions: 1n << 6n, - ViewAuditLog: 1n << 7n, - PrioritySpeaker: 1n << 8n, - Stream: 1n << 9n, - ViewChannel: 1n << 10n, - SendMessages: 1n << 11n, - SendTTSMessages: 1n << 12n, - ManageMessages: 1n << 13n, - EmbedLinks: 1n << 14n, - AttachFiles: 1n << 15n, - ReadMessageHistory: 1n << 16n, - MentionEveryone: 1n << 17n, - UseExternalEmojis: 1n << 18n, - ViewGuildInsights: 1n << 19n, - Connect: 1n << 20n, - Speak: 1n << 21n, - MuteMembers: 1n << 22n, - DeafenMembers: 1n << 23n, - MoveMembers: 1n << 24n, - UseVAD: 1n << 25n, - ChangeNickname: 1n << 26n, - ManageNicknames: 1n << 27n, - ManageRoles: 1n << 28n, - ManageWebhooks: 1n << 29n, - ManageEmojisAndStickers: 1n << 30n, - UseApplicationCommands: 1n << 31n, - RequestToSpeak: 1n << 32n, - ManageEvents: 1n << 33n, - ManageThreads: 1n << 34n, - CreatePublicThreads: 1n << 35n, - CreatePrivateThreads: 1n << 36n, - UseExternalStickers: 1n << 37n, - SendMessagesInThreads: 1n << 38n, - UseEmbeddedActivities: 1n << 39n, - ModerateMembers: 1n << 40n, + CreateInstantInvite: 1n << 0n, + KickMembers: 1n << 1n, + BanMembers: 1n << 2n, + Administrator: 1n << 3n, + ManageChannels: 1n << 4n, + ManageGuild: 1n << 5n, + AddReactions: 1n << 6n, + ViewAuditLog: 1n << 7n, + PrioritySpeaker: 1n << 8n, + Stream: 1n << 9n, + ViewChannel: 1n << 10n, + SendMessages: 1n << 11n, + SendTTSMessages: 1n << 12n, + ManageMessages: 1n << 13n, + EmbedLinks: 1n << 14n, + AttachFiles: 1n << 15n, + ReadMessageHistory: 1n << 16n, + MentionEveryone: 1n << 17n, + UseExternalEmojis: 1n << 18n, + ViewGuildInsights: 1n << 19n, + Connect: 1n << 20n, + Speak: 1n << 21n, + MuteMembers: 1n << 22n, + DeafenMembers: 1n << 23n, + MoveMembers: 1n << 24n, + UseVAD: 1n << 25n, + ChangeNickname: 1n << 26n, + ManageNicknames: 1n << 27n, + ManageRoles: 1n << 28n, + ManageWebhooks: 1n << 29n, + ManageEmojisAndStickers: 1n << 30n, + UseApplicationCommands: 1n << 31n, + RequestToSpeak: 1n << 32n, + ManageEvents: 1n << 33n, + ManageThreads: 1n << 34n, + CreatePublicThreads: 1n << 35n, + CreatePrivateThreads: 1n << 36n, + UseExternalStickers: 1n << 37n, + SendMessagesInThreads: 1n << 38n, + UseEmbeddedActivities: 1n << 39n, + ModerateMembers: 1n << 40n, } \ No newline at end of file diff --git a/enums/permissionStrings.ts b/enums/permissionStrings.ts index d6460ca..3888ca7 100644 --- a/enums/permissionStrings.ts +++ b/enums/permissionStrings.ts @@ -1,43 +1,43 @@ export default { - CreateInstantInvite: "0x0000000000000001", - KickMembers: "0x0000000000000002", - BanMembers: "0x0000000000000004", - Administrator: "0x0000000000000008", - ManageChannels: "0x0000000000000010", - ManageGuild: "0x0000000000000020", - AddReactions: "0x0000000000000040", - ViewAuditLog: "0x0000000000000080", - PrioritySpeaker: "0x0000000000000100", - Stream: "0x0000000000000200", - ViewChannel: "0x0000000000000400", - SendMessages: "0x0000000000000800", - SendTTSMessages: "0x0000000000001000", - ManageMessages: "0x0000000000002000", - EmbedLinks: "0x0000000000004000", - AttachFiles: "0x0000000000008000", - ReadMessageHistory: "0x0000000000010000", - MentionEveryone: "0x0000000000020000", - UseExternalEmojis: "0x0000000000040000", - ViewGuildInsights: "0x0000000000080000", - Connect: "0x0000000000100000", - Speak: "0x0000000000200000", - MuteMembers: "0x0000000000400000", - DeafenMembers: "0x0000000000800000", - MoveMembers: "0x0000000001000000", - UseVAD: "0x0000000002000000", - ChangeNickname: "0x0000000004000000", - ManageNicknames: "0x0000000008000000", - ManageRoles: "0x0000000010000000", - ManageWebhooks: "0x0000000020000000", - ManageEmojisAndStickers: "0x0000000040000000", - UseApplicationCommands: "0x0000000080000000", - RequestToSpeak: "0x0000000100000000", - ManageEvents: "0x0000000200000000", - ManageThreads: "0x0000000400000000", - CreatePublicThreads: "0x0000000800000000", - CreatePrivateThreads: "0x0000001000000000", - UseExternalStickers: "0x0000002000000000", - SendMessagesInThreads: "0x0000004000000000", - UseEmbeddedActivities: "0x0000008000000000", - ModerateMembers: "0x0000010000000000" + CreateInstantInvite: "0x0000000000000001", + KickMembers: "0x0000000000000002", + BanMembers: "0x0000000000000004", + Administrator: "0x0000000000000008", + ManageChannels: "0x0000000000000010", + ManageGuild: "0x0000000000000020", + AddReactions: "0x0000000000000040", + ViewAuditLog: "0x0000000000000080", + PrioritySpeaker: "0x0000000000000100", + Stream: "0x0000000000000200", + ViewChannel: "0x0000000000000400", + SendMessages: "0x0000000000000800", + SendTTSMessages: "0x0000000000001000", + ManageMessages: "0x0000000000002000", + EmbedLinks: "0x0000000000004000", + AttachFiles: "0x0000000000008000", + ReadMessageHistory: "0x0000000000010000", + MentionEveryone: "0x0000000000020000", + UseExternalEmojis: "0x0000000000040000", + ViewGuildInsights: "0x0000000000080000", + Connect: "0x0000000000100000", + Speak: "0x0000000000200000", + MuteMembers: "0x0000000000400000", + DeafenMembers: "0x0000000000800000", + MoveMembers: "0x0000000001000000", + UseVAD: "0x0000000002000000", + ChangeNickname: "0x0000000004000000", + ManageNicknames: "0x0000000008000000", + ManageRoles: "0x0000000010000000", + ManageWebhooks: "0x0000000020000000", + ManageEmojisAndStickers: "0x0000000040000000", + UseApplicationCommands: "0x0000000080000000", + RequestToSpeak: "0x0000000100000000", + ManageEvents: "0x0000000200000000", + ManageThreads: "0x0000000400000000", + CreatePublicThreads: "0x0000000800000000", + CreatePrivateThreads: "0x0000001000000000", + UseExternalStickers: "0x0000002000000000", + SendMessagesInThreads: "0x0000004000000000", + UseEmbeddedActivities: "0x0000008000000000", + ModerateMembers: "0x0000010000000000" } diff --git a/events/discord/guildCreate.ts b/events/discord/guildCreate.ts index c025776..a747c96 100644 --- a/events/discord/guildCreate.ts +++ b/events/discord/guildCreate.ts @@ -5,16 +5,16 @@ import { Guild, ApplicationCommandDataResolvable } from "discord.js"; import Client from "../../types/client"; module.exports = async (client: Client, guild: Guild) => { - const sus = await guildModel.findOne({ guildId: guild.id }); - if (sus) return; + const sus = await guildModel.findOne({ guildId: guild.id }); + if (sus) return; - console.info("Creating MongoDB entry for guild " + guild.name); + console.info("Creating MongoDB entry for guild " + guild.name); - // @ts-ignore - global.functions.addGuildDocument(guild.id); + // @ts-ignore + global.functions.addGuildDocument(guild.id); - client.commands.forEach(command => { - if (command.name === "prepare") return; - guild.commands?.create(command as ApplicationCommandDataResolvable).catch(e => e); - }); + client.commands.forEach(command => { + if (command.name === "prepare") return; + guild.commands?.create(command as ApplicationCommandDataResolvable).catch(e => e); + }); } diff --git a/events/discord/guildDelete.ts b/events/discord/guildDelete.ts index dd24667..7bcbe2c 100644 --- a/events/discord/guildDelete.ts +++ b/events/discord/guildDelete.ts @@ -4,6 +4,6 @@ import { Guild, ApplicationCommandDataResolvable } from "discord.js"; import Client from "../../types/client"; module.exports = async (client: Client, guild: Guild) => { - console.info("Deleting MongoDB entry for guild " + guild.name); - guildModel.findOneAndDelete({ guildId: guild.id }, () => { }); + console.info("Deleting MongoDB entry for guild " + guild.name); + guildModel.findOneAndDelete({ guildId: guild.id }, () => { }); } diff --git a/events/discord/guildMemberAdd.ts b/events/discord/guildMemberAdd.ts index e19fc94..9b5931e 100644 --- a/events/discord/guildMemberAdd.ts +++ b/events/discord/guildMemberAdd.ts @@ -6,9 +6,9 @@ const welcomeMessages = fetchData.get("messages").welcome; import guilds from "../../schemas/guild"; module.exports = async (client: Client, member: GuildMember) => { - const guild = await guilds.findOne({ guildId: member.guild.id }); - if (guild?.channels?.welcome === void 0) return; - const channel = client.channels.cache.get(guild.channels.welcome); - // @ts-expect-error // i gotta stop doing this - channel.send(global.functions.replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); + const guild = await guilds.findOne({ guildId: member.guild.id }); + if (guild?.channels?.welcome === void 0) return; + const channel = client.channels.cache.get(guild.channels.welcome); + // @ts-expect-error // i gotta stop doing this + channel.send(global.functions.replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); } diff --git a/events/discord/messageCreate.ts b/events/discord/messageCreate.ts index 28820cd..5715b7a 100644 --- a/events/discord/messageCreate.ts +++ b/events/discord/messageCreate.ts @@ -4,36 +4,36 @@ import Client from "../../types/client"; import guildModel from "../../schemas/guild"; module.exports = async (client: Client, message: Message) => { - if (message.author.bot) return; // Ignore bots - const guildData = await getGuildData(message.guild!.id); + if (message.author.bot) return; // Ignore bots + const guildData = await getGuildData(message.guild!.id); - // @ts-expect-error // i gotta stop doing this - if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function + // @ts-expect-error // i gotta stop doing this + if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function - // @ts-expect-error // same as above - if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels + // @ts-expect-error // same as above + if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels - const prefix = client.config.prefix; // Get the prefix from the .env file + const prefix = client.config.prefix; // Get the prefix from the .env file - if (!message.content.startsWith(prefix)) return; // Ignore messages that don't start with the prefix + if (!message.content.startsWith(prefix)) return; // Ignore messages that don't start with the prefix - const args = message.content.slice(prefix.length).trim().split(/ +/g); // Get the arguments - const commandString = args.shift()!.toLowerCase(); // Get the command name - const command = client.commands.get("command:" + commandString) || // Get the command from the commands collection - client.commands.find(command => command.aliases && command.aliases.includes(commandString)); - // @ts-expect-error // I am God, I can create whatever I want TS! - message.followUp = message.reply; + const args = message.content.slice(prefix.length).trim().split(/ +/g); // Get the arguments + const commandString = args.shift()!.toLowerCase(); // Get the command name + const command = client.commands.get("command:" + commandString) || // Get the command from the commands collection + client.commands.find(command => command.aliases && command.aliases.includes(commandString)); + // @ts-expect-error // I am God, I can create whatever I want TS! + message.followUp = message.reply; - // @ts-expect-error // i gotta stop doing this - global.functions.executeCommand(command, client, message, args, false); // Execute the command + // @ts-expect-error // i gotta stop doing this + global.functions.executeCommand(command, client, message, args, false); // Execute the command } async function getGuildData(guildId: string) { - let guildData = await guildModel.findOne({ guildId: guildId }); - if (!guildData) { - // @ts-expect-error // i gotta stop doing this - global.functions.addGuildDocument(guildId); - guildData = await guildModel.findOne({ guildId: guildId }); - } - return guildData; + let guildData = await guildModel.findOne({ guildId: guildId }); + if (!guildData) { + // @ts-expect-error // i gotta stop doing this + global.functions.addGuildDocument(guildId); + guildData = await guildModel.findOne({ guildId: guildId }); + } + return guildData; } \ No newline at end of file diff --git a/events/discord/ready.ts b/events/discord/ready.ts index 178dea5..7d91766 100644 --- a/events/discord/ready.ts +++ b/events/discord/ready.ts @@ -1,7 +1,7 @@ import Client from "../../types/client"; module.exports = (client: Client) => { - client.user.setActivity(`${client.config.prefix}help`); - // @ts-expect-error // it really does... - console.success("Bot is ready!"); + client.user.setActivity(`${client.config.prefix}help`); + // @ts-expect-error // it really does... + console.success("Bot is ready!"); } diff --git a/events/mongodb/connected.ts b/events/mongodb/connected.ts index 2a54b12..b4bafee 100644 --- a/events/mongodb/connected.ts +++ b/events/mongodb/connected.ts @@ -1,6 +1,6 @@ import { Connection } from "mongoose"; module.exports = (client: Connection) => { - // @ts-expect-error // gotta add success to the console type - console.success("MongoDB connection is ready!"); + // @ts-expect-error // gotta add success to the console type + console.success("MongoDB connection is ready!"); } diff --git a/events/mongodb/connecting.ts b/events/mongodb/connecting.ts index 279e0db..b16f1e6 100644 --- a/events/mongodb/connecting.ts +++ b/events/mongodb/connecting.ts @@ -1,5 +1,5 @@ import { Connection } from "mongoose"; module.exports = (client: Connection) => { - console.info("Connecting to MongoDB..."); + console.info("Connecting to MongoDB..."); } diff --git a/events/mongodb/disconnected.ts b/events/mongodb/disconnected.ts index 0a27f4e..a67d01d 100644 --- a/events/mongodb/disconnected.ts +++ b/events/mongodb/disconnected.ts @@ -1,5 +1,5 @@ import { Connection } from "mongoose"; module.exports = (client: Connection) => { - console.warn("MongoDB connection destroyed!"); + console.warn("MongoDB connection destroyed!"); } diff --git a/events/mongodb/err.ts b/events/mongodb/err.ts index db9216d..779ac36 100644 --- a/events/mongodb/err.ts +++ b/events/mongodb/err.ts @@ -1,5 +1,5 @@ import { Connection } from "mongoose"; module.exports = (client: Connection, err: Error) => { - console.error(err); + console.error(err); } diff --git a/functions/addGuildDocument.ts b/functions/addGuildDocument.ts index a30546e..463af8a 100644 --- a/functions/addGuildDocument.ts +++ b/functions/addGuildDocument.ts @@ -2,23 +2,23 @@ import guildModel from "../schemas/guild"; import { Types } from "mongoose"; export default (guildId: string) => { - (new guildModel({ - _id: new Types.ObjectId(), - guildId: guildId, + (new guildModel({ + _id: new Types.ObjectId(), + guildId: guildId, - channels: { - welcome: undefined, - goodbye: undefined, + channels: { + welcome: undefined, + goodbye: undefined, - allowed: [] - }, + allowed: [] + }, - counter: { - current: 0, - lastId: undefined, - }, + counter: { + current: 0, + lastId: undefined, + }, - warns: [], - tempBans: [], - })).save(); + warns: [], + tempBans: [], + })).save(); } diff --git a/functions/addUserDocument.ts b/functions/addUserDocument.ts index e7db32c..5c2f4b6cd 100644 --- a/functions/addUserDocument.ts +++ b/functions/addUserDocument.ts @@ -2,8 +2,8 @@ import userModel from "../schemas/user"; const { Types } = require("mongoose"); export default (userId: string) => { - (new userModel({ - _id: Types.ObjectId(), - userId: userId, - })).save(); + (new userModel({ + _id: Types.ObjectId(), + userId: userId, + })).save(); } diff --git a/functions/checkChannelID.ts b/functions/checkChannelID.ts index b509528..006602e 100644 --- a/functions/checkChannelID.ts +++ b/functions/checkChannelID.ts @@ -3,12 +3,12 @@ import { Guild, Message } from "discord.js"; const fetchData = require("./fetchDataFromSave"); module.exports = (message: Message, guildData: any) => { - if (guildData?.channels?.allowed === void 0) return true; - const allowedChannelsIDS = guildData.channels.allowed; - if (Array.isArray(allowedChannelsIDS)) { - if (allowedChannelsIDS.length === 0) return true; - return allowedChannelsIDS.includes(message.channel.id + ""); - } else { - return allowedChannelsIDS === message.channel.id; - } + if (guildData?.channels?.allowed === void 0) return true; + const allowedChannelsIDS = guildData.channels.allowed; + if (Array.isArray(allowedChannelsIDS)) { + if (allowedChannelsIDS.length === 0) return true; + return allowedChannelsIDS.includes(message.channel.id + ""); + } else { + return allowedChannelsIDS === message.channel.id; + } } diff --git a/functions/convertTime.ts b/functions/convertTime.ts index 6e17fff..e891b80 100644 --- a/functions/convertTime.ts +++ b/functions/convertTime.ts @@ -1,28 +1,28 @@ module.exports = (seconds: number) => { - const timeObj = secondsConverter(seconds); - let returnString = ""; - if (timeObj.days > 0) - returnString += `${timeObj.days}d`; - if (timeObj.hours > 0) - returnString += `${timeObj.hours}h`; - if (timeObj.minutes > 0) - returnString += `${timeObj.minutes}m`; - if (timeObj.seconds > 0) - returnString += `${timeObj.seconds}s`; - if (returnString !== "") - return returnString; - else - return "0s"; + const timeObj = secondsConverter(seconds); + let returnString = ""; + if (timeObj.days > 0) + returnString += `${timeObj.days}d`; + if (timeObj.hours > 0) + returnString += `${timeObj.hours}h`; + if (timeObj.minutes > 0) + returnString += `${timeObj.minutes}m`; + if (timeObj.seconds > 0) + returnString += `${timeObj.seconds}s`; + if (returnString !== "") + return returnString; + else + return "0s"; } function secondsConverter(seconds: number) { - const timeObj: any = {}; - timeObj.days = Math.floor(seconds / 86400); - seconds -= timeObj.days * 86400; - timeObj.hours = Math.floor(seconds / 3600); - seconds -= timeObj.hours * 3600; - timeObj.minutes = Math.floor(seconds / 60); - seconds -= timeObj.minutes * 60; - timeObj.seconds = Math.floor(seconds); - return timeObj; + const timeObj: any = {}; + timeObj.days = Math.floor(seconds / 86400); + seconds -= timeObj.days * 86400; + timeObj.hours = Math.floor(seconds / 3600); + seconds -= timeObj.hours * 3600; + timeObj.minutes = Math.floor(seconds / 60); + seconds -= timeObj.minutes * 60; + timeObj.seconds = Math.floor(seconds); + return timeObj; } \ No newline at end of file diff --git a/functions/counter.ts b/functions/counter.ts index 91fe813..83c22f5 100644 --- a/functions/counter.ts +++ b/functions/counter.ts @@ -3,16 +3,16 @@ import { Message } from "discord.js"; import guilds from "../schemas/guild"; module.exports = (message: Message, guildData: any) => { - ; - if (guildData?.channels?.counter === void 0) return; - if (!(guildData.channels.counter === message.channel.id)) return false; - const current = guildData.counter.current; - if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) - guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: any) => { - if (err) console.error(err); - (err); - if (!data) return "No data found" - }); - else message.delete().catch(); - return true; + ; + if (guildData?.channels?.counter === void 0) return; + if (!(guildData.channels.counter === message.channel.id)) return false; + const current = guildData.counter.current; + if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) + guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: any) => { + if (err) console.error(err); + (err); + if (!data) return "No data found" + }); + else message.delete().catch(); + return true; } diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index 66d8223..a590b8e 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -12,191 +12,191 @@ import sendMessage from "./sendMessage"; module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { - if (command === void 0) return; - - // @ts-expect-error - interaction.author ||= interaction.message.author; - - if (command.default_member_permissions - && !isInteraction - && !interaction!.member!.permissions.has(command!.default_member_permissions as PermissionResolvable)) { - const permissionString = getPermissionsString(command.default_member_permissions); - const moreThanOne = (permissionString.match(/,/g) || []).length; - const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; - return interaction.reply(outputString); - } - - if (command!.commandOptions?.connectedToSameVC) - command!.commandOptions.connectedToVC = true; - - if (command!.commandOptions?.connectedToVC && !interaction!.member!.voice?.channel) - return interaction.reply("You need to be in a voice channel to use this command."); - - if (command!.commandOptions?.connectedToSameVC && client!.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction!.member!.voice?.channel?.id) { - if (client.player.getQueue(interaction.guildId)?.voiceChannel === void 0) - return interaction.reply("I am not in a voice channel."); - return interaction.reply("You need to be in the same voice channel as me to use this command."); - } - - const cooldownReturn = checkCooldown(command, interaction, client); - if (typeof cooldownReturn === "string") return interaction.reply(cooldownReturn); - - // makes reply unavailable so two replies can't be sent - const reply = interaction.reply; - interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand. Use return or message.channel.send() instead!") }; - // @ts-expect-error - const deferReply = interaction.deferReply; - // @ts-expect-error - interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand. Use return null instead!") }; - - try { - if (command!.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); - - let guildData; - if (interaction.guild) - guildData = await getGuildData(interaction.guild.id); - - let userData = await getUserData(interaction.author.id); - - let returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); - - if (returnValue === null) { - // @ts-expect-error - interaction.deferReply = deferReply; - // @ts-expect-error - if (isInteraction) interaction.deferReply(); - return; - } - - // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - let success = returnValue.success || command!.commandOptions?.defaultReturn?.success; - - if (success) { - if (returnValue!.setCooldown) - returnValue.setCooldown.push(command); - else - returnValue!.setCooldown = [command]; - } - - // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - let cooldownArray: Command[] | undefined = returnValue!.setCooldown || command!.commandOptions?.defaultReturn?.setCooldown; - - if (cooldownArray !== void 0) - cooldownArray.forEach(commandObject => { - setCooldown(commandObject, interaction, client); - }); - - // makes reply available again - interaction.reply = reply; - - if (returnValue.DM !== void 0 && returnValue.DM !== null) { - sendMessage(returnValue.DM, command, client, interaction, args, isInteraction, guildData, userData, true); - } - - if (interaction.guildId === null) returnValue.announce = true; - sendMessage(returnValue, command, client, interaction, args, isInteraction, guildData, userData, false); - - // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - const disable = returnValue.disableOriginal || command!.commandOptions?.defaultReturn?.disableOriginal; - if (disable && isComponent) { - // @ts-expect-error - const originalMessage = await interaction.message; - // @ts-expect-error - originalMessage.components.forEach(actionRow => { - // @ts-expect-error - actionRow.components.forEach(component => { - component.data.disabled = true; - }); - }); - if (originalMessage.content) originalMessage.content += "\n\nThis message has been \u202B\u202B and is now disabled"; - else originalMessage.content = "This message has been \u202B\u202B and is now disabled"; - originalMessage.edit({ content: originalMessage.content, components: originalMessage.components }).catch(() => { }); - } - } catch (e) { - // makes reply available again - interaction.reply = reply; - // @ts-expect-error - if (isInteraction) interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(() => { }); - else interaction.reply("An error occurred while executing this command.").catch(() => { }); - console.error(e); - } + if (command === void 0) return; + + // @ts-expect-error + interaction.author ||= interaction.message.author; + + if (command.default_member_permissions + && !isInteraction + && !interaction!.member!.permissions.has(command!.default_member_permissions as PermissionResolvable)) { + const permissionString = getPermissionsString(command.default_member_permissions); + const moreThanOne = (permissionString.match(/,/g) || []).length; + const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; + return interaction.reply(outputString); + } + + if (command!.commandOptions?.connectedToSameVC) + command!.commandOptions.connectedToVC = true; + + if (command!.commandOptions?.connectedToVC && !interaction!.member!.voice?.channel) + return interaction.reply("You need to be in a voice channel to use this command."); + + if (command!.commandOptions?.connectedToSameVC && client!.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction!.member!.voice?.channel?.id) { + if (client.player.getQueue(interaction.guildId)?.voiceChannel === void 0) + return interaction.reply("I am not in a voice channel."); + return interaction.reply("You need to be in the same voice channel as me to use this command."); + } + + const cooldownReturn = checkCooldown(command, interaction, client); + if (typeof cooldownReturn === "string") return interaction.reply(cooldownReturn); + + // makes reply unavailable so two replies can't be sent + const reply = interaction.reply; + interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand. Use return or message.channel.send() instead!") }; + // @ts-expect-error + const deferReply = interaction.deferReply; + // @ts-expect-error + interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand. Use return null instead!") }; + + try { + if (command!.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); + + let guildData; + if (interaction.guild) + guildData = await getGuildData(interaction.guild.id); + + let userData = await getUserData(interaction.author.id); + + let returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); + + if (returnValue === null) { + // @ts-expect-error + interaction.deferReply = deferReply; + // @ts-expect-error + if (isInteraction) interaction.deferReply(); + return; + } + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + let success = returnValue.success || command!.commandOptions?.defaultReturn?.success; + + if (success) { + if (returnValue!.setCooldown) + returnValue.setCooldown.push(command); + else + returnValue!.setCooldown = [command]; + } + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + let cooldownArray: Command[] | undefined = returnValue!.setCooldown || command!.commandOptions?.defaultReturn?.setCooldown; + + if (cooldownArray !== void 0) + cooldownArray.forEach(commandObject => { + setCooldown(commandObject, interaction, client); + }); + + // makes reply available again + interaction.reply = reply; + + if (returnValue.DM !== void 0 && returnValue.DM !== null) { + sendMessage(returnValue.DM, command, client, interaction, args, isInteraction, guildData, userData, true); + } + + if (interaction.guildId === null) returnValue.announce = true; + sendMessage(returnValue, command, client, interaction, args, isInteraction, guildData, userData, false); + + // @ts-expect-error // cause if it's undefined, it's not doing anything anyway + const disable = returnValue.disableOriginal || command!.commandOptions?.defaultReturn?.disableOriginal; + if (disable && isComponent) { + // @ts-expect-error + const originalMessage = await interaction.message; + // @ts-expect-error + originalMessage.components.forEach(actionRow => { + // @ts-expect-error + actionRow.components.forEach(component => { + component.data.disabled = true; + }); + }); + if (originalMessage.content) originalMessage.content += "\n\nThis message has been \u202B\u202B and is now disabled"; + else originalMessage.content = "This message has been \u202B\u202B and is now disabled"; + originalMessage.edit({ content: originalMessage.content, components: originalMessage.components }).catch(() => { }); + } + } catch (e) { + // makes reply available again + interaction.reply = reply; + // @ts-expect-error + if (isInteraction) interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(() => { }); + else interaction.reply("An error occurred while executing this command.").catch(() => { }); + console.error(e); + } } // function that converts default_member_permissions bitfield to a human readable string function getPermissionsString(permissionString: string) { - const permissions = parseInt(permissionString); - if (permissions === 0) return "None"; - if (permissions === 8) return "Administrator"; - if (permissions === 2147483647) return "All"; - const perms = []; - if (permissions & 1) perms.push("Create Instant Invite"); - if (permissions & 2) perms.push("Kick Members"); - if (permissions & 4) perms.push("Ban Members"); - if (permissions & 8) perms.push("Administrator"); - if (permissions & 16) perms.push("Manage Channels"); - if (permissions & 32) perms.push("Manage Guild"); - if (permissions & 64) perms.push("Add Reactions"); - if (permissions & 128) perms.push("View Audit Log"); - if (permissions & 256) perms.push("Priority Speaker"); - if (permissions & 512) perms.push("Stream"); - if (permissions & 1024) perms.push("View Channel"); - if (permissions & 2048) perms.push("Send Messages"); - if (permissions & 4096) perms.push("Send TTS Messages"); - if (permissions & 8192) perms.push("Manage Messages"); - if (permissions & 16384) perms.push("Embed Links"); - if (permissions & 32768) perms.push("Attach Files"); - if (permissions & 65536) perms.push("Read Message History"); - if (permissions & 131072) perms.push("Mention Everyone"); - if (permissions & 262144) perms.push("Use External Emojis"); - if (permissions & 524288) perms.push("View Guild Insights"); - if (permissions & 1048576) perms.push("Connect"); - if (permissions & 2097152) perms.push("Speak"); - if (permissions & 4194304) perms.push("Mute Members"); - if (permissions & 8388608) perms.push("Deafen Members"); - if (permissions & 16777216) perms.push("Move Members"); - if (permissions & 33554432) perms.push("Use VAD"); - if (permissions & 67108864) perms.push("Change Nickname"); - if (permissions & 134217728) perms.push("Manage Nicknames"); - if (permissions & 268435456) perms.push("Manage Roles"); - if (permissions & 536870912) perms.push("Manage Webhooks"); - if (permissions & 1073741824) perms.push("Manage Emojis"); - return perms.join(", "); + const permissions = parseInt(permissionString); + if (permissions === 0) return "None"; + if (permissions === 8) return "Administrator"; + if (permissions === 2147483647) return "All"; + const perms = []; + if (permissions & 1) perms.push("Create Instant Invite"); + if (permissions & 2) perms.push("Kick Members"); + if (permissions & 4) perms.push("Ban Members"); + if (permissions & 8) perms.push("Administrator"); + if (permissions & 16) perms.push("Manage Channels"); + if (permissions & 32) perms.push("Manage Guild"); + if (permissions & 64) perms.push("Add Reactions"); + if (permissions & 128) perms.push("View Audit Log"); + if (permissions & 256) perms.push("Priority Speaker"); + if (permissions & 512) perms.push("Stream"); + if (permissions & 1024) perms.push("View Channel"); + if (permissions & 2048) perms.push("Send Messages"); + if (permissions & 4096) perms.push("Send TTS Messages"); + if (permissions & 8192) perms.push("Manage Messages"); + if (permissions & 16384) perms.push("Embed Links"); + if (permissions & 32768) perms.push("Attach Files"); + if (permissions & 65536) perms.push("Read Message History"); + if (permissions & 131072) perms.push("Mention Everyone"); + if (permissions & 262144) perms.push("Use External Emojis"); + if (permissions & 524288) perms.push("View Guild Insights"); + if (permissions & 1048576) perms.push("Connect"); + if (permissions & 2097152) perms.push("Speak"); + if (permissions & 4194304) perms.push("Mute Members"); + if (permissions & 8388608) perms.push("Deafen Members"); + if (permissions & 16777216) perms.push("Move Members"); + if (permissions & 33554432) perms.push("Use VAD"); + if (permissions & 67108864) perms.push("Change Nickname"); + if (permissions & 134217728) perms.push("Manage Nicknames"); + if (permissions & 268435456) perms.push("Manage Roles"); + if (permissions & 536870912) perms.push("Manage Webhooks"); + if (permissions & 1073741824) perms.push("Manage Emojis"); + return perms.join(", "); } function setCooldown(commandString: Command | string, interaction: Message, client: Client) { - let command: Command; - if (typeof commandString === "string") { - const getCommand = client.commands.get(commandString); - if (getCommand === void 0) return console.error("Could not set cooldown, command not found: " + commandString); - command = getCommand; - } else - command = commandString; - if (typeof command!.commandOptions?.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + command.name); - if (command.name === void 0) return console.error("Could not set cooldown, command has no name: " + command.name); - client.commandCooldowns.get(command.name)!.set(interaction!.author.id, Date.now() + command!.commandOptions?.cooldown * 1000); - setTimeout(() => { - client.commandCooldowns.get(command.name as string)!.delete(interaction!.author.id); - }, command!.commandOptions?.cooldown * 1000); + let command: Command; + if (typeof commandString === "string") { + const getCommand = client.commands.get(commandString); + if (getCommand === void 0) return console.error("Could not set cooldown, command not found: " + commandString); + command = getCommand; + } else + command = commandString; + if (typeof command!.commandOptions?.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + command.name); + if (command.name === void 0) return console.error("Could not set cooldown, command has no name: " + command.name); + client.commandCooldowns.get(command.name)!.set(interaction!.author.id, Date.now() + command!.commandOptions?.cooldown * 1000); + setTimeout(() => { + client.commandCooldowns.get(command.name as string)!.delete(interaction!.author.id); + }, command!.commandOptions?.cooldown * 1000); } function checkCooldown(commandString: Command | string, interaction: Message, client: Client): string | boolean { - let command: Command; - if (typeof commandString === "string") { - const getCommand = client.commands.get(commandString); - if (getCommand === void 0) throw new Error("Could not check cooldown, command not found: " + commandString); - command = getCommand; - } else - command = commandString; - if (command.name === void 0) throw new Error("Could not check cooldown, command has no name: " + command.name); - if (client.commandCooldowns.get(command.name)!.has(interaction!.author.id)) { - let timeLeft = client.commandCooldowns.get(command.name)!.get(interaction!.author.id)! - Date.now(); - timeLeft /= 1000; - if (timeLeft > 0) { - // @ts-expect-error - const timeString = global.functions.convertTime(timeLeft); - return `You are on cooldown for this command, please wait ${timeString}.` - } - } - return false; + let command: Command; + if (typeof commandString === "string") { + const getCommand = client.commands.get(commandString); + if (getCommand === void 0) throw new Error("Could not check cooldown, command not found: " + commandString); + command = getCommand; + } else + command = commandString; + if (command.name === void 0) throw new Error("Could not check cooldown, command has no name: " + command.name); + if (client.commandCooldowns.get(command.name)!.has(interaction!.author.id)) { + let timeLeft = client.commandCooldowns.get(command.name)!.get(interaction!.author.id)! - Date.now(); + timeLeft /= 1000; + if (timeLeft > 0) { + // @ts-expect-error + const timeString = global.functions.convertTime(timeLeft); + return `You are on cooldown for this command, please wait ${timeString}.` + } + } + return false; } \ No newline at end of file diff --git a/functions/fetchDataFromSave.ts b/functions/fetchDataFromSave.ts index 5ca5d47..515b455 100644 --- a/functions/fetchDataFromSave.ts +++ b/functions/fetchDataFromSave.ts @@ -2,18 +2,18 @@ const data = require("../data.json"); import fs from "fs"; module.exports = { - all: () => { - return data; - }, - get: (key: string) => { - return data[key]; - }, - set: (key: string, value: any) => { - data[key] = value; - }, - write: () => { - const wStream = fs.createWriteStream("./data.json", "utf-8"); - wStream.write(JSON.stringify(data)); - wStream.end(); - } + all: () => { + return data; + }, + get: (key: string) => { + return data[key]; + }, + set: (key: string, value: any) => { + data[key] = value; + }, + write: () => { + const wStream = fs.createWriteStream("./data.json", "utf-8"); + wStream.write(JSON.stringify(data)); + wStream.end(); + } } diff --git a/functions/formatCommandReturn.ts b/functions/formatCommandReturn.ts index c406c5c..566e512 100644 --- a/functions/formatCommandReturn.ts +++ b/functions/formatCommandReturn.ts @@ -3,27 +3,27 @@ import { Command, CommandReturns } from "../types/command"; const { Message } = require("discord.js"); module.exports = async (returnValue: any, command: Command) => { - return await new Promise(async (resolve, reject) => { - if (returnValue instanceof Promise) { - const timeout = setTimeout(() => { - reject(`Command ${command.name} took too long to execute!`); - }, 4500); - returnValue = await returnValue; - clearTimeout(timeout); - } - if (( - (typeof returnValue === "string" && returnValue !== "") - || returnValue?.embeds !== void 0 - || returnValue?.files !== void 0 - || returnValue?.components !== void 0 - || returnValue?.content !== void 0 - || returnValue?.files !== void 0 - || returnValue?.attachments !== void 0 - ) && !(returnValue instanceof Message)) { - if (typeof returnValue === "string") returnValue = { content: returnValue }; - } else if (returnValue?.DM !== void 0) { - returnValue.DM = module.exports(returnValue.DM, command); - } else if (returnValue !== null) reject(`Command "${command.name}" returned nothing.`); - resolve(returnValue); - }); + return await new Promise(async (resolve, reject) => { + if (returnValue instanceof Promise) { + const timeout = setTimeout(() => { + reject(`Command ${command.name} took too long to execute!`); + }, 4500); + returnValue = await returnValue; + clearTimeout(timeout); + } + if (( + (typeof returnValue === "string" && returnValue !== "") + || returnValue?.embeds !== void 0 + || returnValue?.files !== void 0 + || returnValue?.components !== void 0 + || returnValue?.content !== void 0 + || returnValue?.files !== void 0 + || returnValue?.attachments !== void 0 + ) && !(returnValue instanceof Message)) { + if (typeof returnValue === "string") returnValue = { content: returnValue }; + } else if (returnValue?.DM !== void 0) { + returnValue.DM = module.exports(returnValue.DM, command); + } else if (returnValue !== null) reject(`Command "${command.name}" returned nothing.`); + resolve(returnValue); + }); } \ No newline at end of file diff --git a/functions/getChannelFromMention.ts b/functions/getChannelFromMention.ts index bc5129d..438d2c3 100644 --- a/functions/getChannelFromMention.ts +++ b/functions/getChannelFromMention.ts @@ -1,6 +1,6 @@ import { Guild } from "discord.js"; module.exports = (guild: Guild, mention: string) => { - if (!mention) return; - return guild.channels.cache.get(mention.substring(2, mention.length - 1)); + if (!mention) return; + return guild.channels.cache.get(mention.substring(2, mention.length - 1)); } diff --git a/functions/getFiles.ts b/functions/getFiles.ts index c3ba339..56f2db4 100644 --- a/functions/getFiles.ts +++ b/functions/getFiles.ts @@ -1,17 +1,17 @@ const fs = require("fs"); const getFiles = (dir: string, exclude = null) => { - const output: any = {}; - fs.readdirSync(dir).forEach((path: string) => { - if (fs.lstatSync(dir + "/" + path).isDirectory()) { - output[path] = getFiles(dir + "/" + path, exclude); - } else { - if (!path.endsWith(".js") && !path.endsWith(".ts")) return; - const func = require(`.${dir}/${path}`); - output[path.replace(".js", "").replace(".ts", "")] = func; - } - }); - return output; + const output: any = {}; + fs.readdirSync(dir).forEach((path: string) => { + if (fs.lstatSync(dir + "/" + path).isDirectory()) { + output[path] = getFiles(dir + "/" + path, exclude); + } else { + if (!path.endsWith(".js") && !path.endsWith(".ts")) return; + const func = require(`.${dir}/${path}`); + output[path.replace(".js", "").replace(".ts", "")] = func; + } + }); + return output; } module.exports = getFiles; diff --git a/functions/getGuildData.ts b/functions/getGuildData.ts index b70e580..b576654 100644 --- a/functions/getGuildData.ts +++ b/functions/getGuildData.ts @@ -2,10 +2,10 @@ import guildModel from "../schemas/guild"; import addGuildDocument from "./addGuildDocument"; export default async (guildId: string) => { - let guildData = await guildModel.findOne({ guildId: guildId }); - if (!guildData) { - addGuildDocument(guildId); - guildData = await guildModel.findOne({ guildId: guildId }); - } - return guildData; + let guildData = await guildModel.findOne({ guildId: guildId }); + if (!guildData) { + addGuildDocument(guildId); + guildData = await guildModel.findOne({ guildId: guildId }); + } + return guildData; } diff --git a/functions/getUserData.ts b/functions/getUserData.ts index 1354cff..1fa32bc 100644 --- a/functions/getUserData.ts +++ b/functions/getUserData.ts @@ -2,10 +2,10 @@ import userModel from "../schemas/user"; import addUserDocument from "./addUserDocument"; export default async (userId: string) => { - let userData = await userModel.findOne({ userId: userId }); - if (!userData) { - addUserDocument(userId); - userData = await userModel.findOne({ userId: userId }); - } - return userData; + let userData = await userModel.findOne({ userId: userId }); + if (!userData) { + addUserDocument(userId); + userData = await userModel.findOne({ userId: userId }); + } + return userData; } diff --git a/functions/replaceUser.ts b/functions/replaceUser.ts index 2e47c0c..564bab1 100644 --- a/functions/replaceUser.ts +++ b/functions/replaceUser.ts @@ -1,5 +1,5 @@ import { GuildMember } from "discord.js"; module.exports = (message: string, member: GuildMember) => { - return message.replace("{user}", "**" + member.user.username + "#" + member.user.discriminator + "**"); + return message.replace("{user}", "**" + member.user.username + "#" + member.user.discriminator + "**"); } diff --git a/functions/sendMessage.ts b/functions/sendMessage.ts index 05c9dc1..0518c52 100644 --- a/functions/sendMessage.ts +++ b/functions/sendMessage.ts @@ -1,61 +1,61 @@ -import { Message, Component, ActionRow, ButtonComponent, BaseSelectMenuComponent } from "discord.js"; +import { Message, Component, ButtonComponent, BaseSelectMenuComponent } from "discord.js"; import Client from "../types/client"; import { Command, CommandReturnWithoutString } from "../types/command"; export default async (messageToSend: CommandReturnWithoutString, command: Command, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: any /*idfk*/, userData: any /*same here*/, isDM: boolean) => { - let sentMessage: Message; - - if (messageToSend === null) return; - - if (messageToSend.announce || isDM) - // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need - messageToSend.ephemeral = false; - else - // @ts-expect-error // same as above - messageToSend.ephemeral = true; - - if (messageToSend.deleteMessage && !isInteraction) message.delete(); - - // @ts-expect-error // same as above - if (messageToSend.ephemeral && isInteraction) messageToSend.deleteReply = false; // ephemeral messages can't be deleted - - if (messageToSend.disableMentions) messageToSend.allowedMentions = { parse: [] }; - - // @ts-expect-error // same as above - messageToSend.failIfNotExists = false; - - if (isDM) { - // @ts-expect-error // same as above - sentMessage = await message.author.send(messageToSend); - } - else - // @ts-expect-error // same as above - sentMessage = await message.reply(messageToSend); - - if (messageToSend.deleteReply) { - if (messageToSend.deleteReply === true) messageToSend.deleteReply = 5; - setTimeout(() => { - // @ts-expect-error // idk what I did wrong here, but it's not a big deal, I hope - if (isInteraction) message.deleteReply(); - else sentMessage.delete(); - }, messageToSend.deleteReply * 1000); - } - - if (messageToSend.disable) { - if (messageToSend.disable === true) messageToSend.disable = 5; - setTimeout(() => { - messageToSend.components!.forEach((actionRow: any) => { - actionRow.components.forEach((component: Component) => { - if (component instanceof ButtonComponent || component instanceof BaseSelectMenuComponent) { - // @ts-expect-error // I do, in fact, know what I'm doing TS... Idfc if it's read-only or not - component.disabled = true; - } - }); - }); - // @ts-expect-error // I do think it does exist but I just selected the wrong type bc I want to finish this as soon as possible // FIXME - if (isInteraction) message.editReply(messageToSend); - // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need - else sentMessage.edit(messageToSend); - }, messageToSend.disable * 1000); - } -} \ No newline at end of file + let sentMessage: Message; + + if (messageToSend === null) return; + + if (messageToSend.announce || isDM) + // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need + messageToSend.ephemeral = false; + else + // @ts-expect-error // same as above + messageToSend.ephemeral = true; + + if (messageToSend.deleteMessage && !isInteraction) message.delete(); + + // @ts-expect-error // same as above + if (messageToSend.ephemeral && isInteraction) messageToSend.deleteReply = false; // ephemeral messages can't be deleted + + if (messageToSend.disableMentions) messageToSend.allowedMentions = { parse: [] }; + + // @ts-expect-error // same as above + messageToSend.failIfNotExists = false; + + if (isDM) { + // @ts-expect-error // same as above + sentMessage = await message.author.send(messageToSend); + } + else + // @ts-expect-error // same as above + sentMessage = await message.reply(messageToSend); + + if (messageToSend.deleteReply) { + if (messageToSend.deleteReply === true) messageToSend.deleteReply = 5; + setTimeout(() => { + // @ts-expect-error // idk what I did wrong here, but it's not a big deal, I hope + if (isInteraction) message.deleteReply(); + else sentMessage.delete(); + }, messageToSend.deleteReply * 1000); + } + + if (messageToSend.disable) { + if (messageToSend.disable === true) messageToSend.disable = 5; + setTimeout(() => { + messageToSend.components!.forEach((actionRow: any) => { + actionRow.components.forEach((component: Component) => { + if (component instanceof ButtonComponent || component instanceof BaseSelectMenuComponent) { + // @ts-expect-error // I do, in fact, know what I'm doing TS... Idfc if it's read-only or not + component.disabled = true; + } + }); + }); + // @ts-expect-error // I do think it does exist but I just selected the wrong type bc I want to finish this as soon as possible // FIXME + if (isInteraction) message.editReply(messageToSend); + // @ts-expect-error // I know what I'm doing... I'll just ignore whatever attributes I attached that it doesn't need + else sentMessage.edit(messageToSend); + }, messageToSend.disable * 1000); + } +}; \ No newline at end of file diff --git a/functions/shuffle.ts b/functions/shuffle.ts index a5e5f14..d53f9c7 100644 --- a/functions/shuffle.ts +++ b/functions/shuffle.ts @@ -1,8 +1,8 @@ module.exports = (arrayIn: any[]) => { - let array = arrayIn; - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - return array; + let array = arrayIn; + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; } diff --git a/index.ts b/index.ts index 378680f..f7b95b0 100644 --- a/index.ts +++ b/index.ts @@ -16,13 +16,13 @@ require("better-cl").setup(console, [], "./logs"); console.clear(); const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildVoiceStates, - GatewayIntentBits.MessageContent - ] + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.MessageContent + ] }) as ModifiedClient; /* add important stuff to client */ @@ -39,33 +39,33 @@ global.functions = require("./functions/getFiles")("./functions", "functions.ts" /* Loading all the commands. */ [ - "commands", - "buttons", - "selectMenus" + "commands", + "buttons", + "selectMenus" ].forEach((name) => loadCommands(name, true)); client.commandCooldowns = new Collection(); client.commands.forEach((command: Command) => { - client.commandCooldowns.set(command.name!, new Collection()); + client.commandCooldowns.set(command.name!, new Collection()); }); const eventToClientMap = { - discord: client, - mongodb: connection + discord: client, + mongodb: connection }; /* Loading all the events. */ fs.readdirSync("./events").forEach((dir: string) => { - if (!fs.lstatSync("./events/" + dir).isDirectory()) - return console.warn(`The file ./events/${dir} is not a directory.`); - // @ts-expect-error - if (!eventToClientMap[dir]) - return console.warn(`The event folder ${dir} is not valid!`); - console.log(`Loading ${dir} events...`); - fs.readdirSync(`./events/${dir}`).filter((e: string) => e.endsWith(".ts")).forEach((event: string) => { - // @ts-expect-error - eventToClientMap[dir].on(event.split(".")[0], require(`./events/${dir}/${event}`).bind(null, client)); - }); + if (!fs.lstatSync("./events/" + dir).isDirectory()) + return console.warn(`The file ./events/${dir} is not a directory.`); + // @ts-expect-error + if (!eventToClientMap[dir]) + return console.warn(`The event folder ${dir} is not valid!`); + console.log(`Loading ${dir} events...`); + fs.readdirSync(`./events/${dir}`).filter((e: string) => e.endsWith(".ts")).forEach((event: string) => { + // @ts-expect-error + eventToClientMap[dir].on(event.split(".")[0], require(`./events/${dir}/${event}`).bind(null, client)); + }); }); module.exports = client; @@ -81,22 +81,22 @@ require("./www/index").startServer(client, process.env.PORT, () => console.succe // makes sure the bot doesn't crash process.on("uncaughtException", (err) => { - console.error(err); + console.error(err); }); function loadCommands(dirName: string, removeTrailingS = true) { - let dirNameCollection = dirName; - if (removeTrailingS) dirNameCollection = dirName.replace(/s$/, ""); - fs.readdirSync(`./${dirName}`).forEach((dir: string) => { - if (!fs.lstatSync(`./${dirName}/` + dir).isDirectory()) - return console.warn(`./${dirName}/${dir} is not a directory.`); - fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { - const command = require(`./${dirName}/${dir}/${file}`); - if (command.ignore) return; - command.category = `${dirNameCollection}:` + dir; - command.name ||= file.replace(/(\.ts)$/, ""); - command.name = `${dirNameCollection}:` + command.name.toLowerCase(); - client.commands.set(command.name, command); - }) - }); + let dirNameCollection = dirName; + if (removeTrailingS) dirNameCollection = dirName.replace(/s$/, ""); + fs.readdirSync(`./${dirName}`).forEach((dir: string) => { + if (!fs.lstatSync(`./${dirName}/` + dir).isDirectory()) + return console.warn(`./${dirName}/${dir} is not a directory.`); + fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { + const command = require(`./${dirName}/${dir}/${file}`); + if (command.ignore) return; + command.category = `${dirNameCollection}:` + dir; + command.name ||= file.replace(/(\.ts)$/, ""); + command.name = `${dirNameCollection}:` + command.name.toLowerCase(); + client.commands.set(command.name, command); + }) + }); } \ No newline at end of file diff --git a/music/player.js b/music/player.js index 18f061b..83571df 100644 --- a/music/player.js +++ b/music/player.js @@ -4,353 +4,351 @@ const { ImprovedArray } = require("sussy-util"); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } = require("discord.js"); const playerControls = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId('command:queue') - .setLabel('☰') - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId('play_pause') - .setLabel('׀׀') - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId('command:stop') - .setLabel('◼') - .setStyle(ButtonStyle.Danger), - new ButtonBuilder() - .setCustomId('command:skip') - .setLabel('>>') - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId('support') - .setLabel('Support us!') - .setStyle(ButtonStyle.Secondary), - ); + .addComponents( + new ButtonBuilder() + .setCustomId("command:queue") + .setLabel("☰") + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId("play_pause") + .setLabel("׀׀") + .setStyle(ButtonStyle.Success), + new ButtonBuilder() + .setCustomId("command:stop") + .setLabel("◼") + .setStyle(ButtonStyle.Danger), + new ButtonBuilder() + .setCustomId("command:skip") + .setLabel(">>") + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId("support") + .setLabel("Support us!") + .setStyle(ButtonStyle.Secondary), + ); module.exports = class Player { - //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? - //TODO: Add previous function --> Completely rewrite the queue system - //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) - //TODO: Add Spotify support - //TODO: Add Soundcloud support - //TODO: Don't get sued by YouTube - //TODO: Complete rewrite of the player - //BUG: See issue #17 - - #queue = new Map(); - #client; - - constructor(client) { - this.#client = client; - - this.#client.on("voiceStateUpdate", (oldState, newState) => { - const queue = this.getQueue(newState.guild.id); - - if (queue === undefined || oldState.channelId === null) { - return; - } - - if (oldState.id !== this.#client.user.id) { - if (this.#channelEmpty(oldState.channelId)) { - queue.current.channel.send("Leaving channel because it is empty."); - this.#destroyQueue(newState.guild.id); - } - return; - } - if (newState.channelId === undefined) { - queue.current.channel.send("I have been kicked from the channel."); - this.#destroyQueue(newState.guild.id); - } - - if (oldState.channelId !== newState.channelId) { - queue.voiceChannel = newState.channelId; - client.voiceChannel = newState.channelId; - } - }); - } - - #newQueue(guildId) { - this.#queue.set(guildId, { - connection: null, - voiceChannel: null, - player: null, - current: null, - loop: false, - guildId: null, - queue: new ImprovedArray() - }); - } - - #destroyQueue(guildId) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); - } - guildInfo.connection.destroy(); - this.#queue.delete(guildId); - } - - async play(guildId, track) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; - guildInfo.current = track; - - const stream = await AudioStream(track.url); - const resource = createAudioResource(stream.stream, { inputType: stream.type }); - - guildInfo.player.play(resource); - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); - } - guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); - } - - async #createEmbed(info, type) { - const embed = new EmbedBuilder() - .setURL(info.url) - .setColor(Colors.Red) - .setTimestamp(new Date()) - .setFooter(this.#client.config.embedFooter(this.#client)); - - if (info.title) { - embed.setTitle(`${type} track ${info.title}`); - } - - if (info.thumbnails) { - const thumbnail = info.thumbnails[info.thumbnails.length - 1]; - if (thumbnail) { - embed.setImage(thumbnail.url); - } - } - - return embed; - } - - async addTrack(message, args) { - if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; - - let videoName = args.map(e => e.trim()).join(" ").trim(); - - if (videoName === "") return "Please enter the link/name of the track"; - - let url; - if (videoName.startsWith("https") && yt_validate(videoName) === "video") { - url = videoName; - } else { - const yt_infos = await search(args.join(" "), { limit: 10 }); - let currentInfo = 0; - do { - url = yt_infos[currentInfo].url; - currentInfo++; - } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); - } - - let info; - try { - info = (await video_basic_info(url)).video_details; - } catch (err) { - - } - if (info === undefined) { - if (this.#queue.get(message.guild.id)?.queue.length === 0) return; - let returnValue = this.skip(message); - returnValue.content = "Can't play tracks requiring age verification! Skipping..."; - return returnValue; - } - - if (!this.#queue.has(message.guild.id)) { - this.#newQueue(message.guild.id); - const queue = this.#queue.get(message.guild.id); - const connection = joinVoiceChannel({ - channelId: message.member.voice.channel.id, - guildId: message.guild.id, - adapterCreator: message.guild.voiceAdapterCreator - }); - - const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); - connection.subscribe(player); - - queue.connection = connection; - queue.player = player; - queue.voiceChannel = message.member.voice.channel.id; - this.#client.voiceChannel = message.member.voice.channel.id; - queue.guildId = message.guild.id; - - queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { - try { - await Promise.race([ - entersState(connection, VoiceConnectionStatus.Signalling, 5_000), - entersState(connection, VoiceConnectionStatus.Connecting, 5_000), - ]); - } catch (error) { - this.#destroyQueue(queue.guildId); - return "There was an error connecting to the voice channel."; - } - }); - - queue.player.on("error", (err) => { - message.channel.send("An error occurred while playing the track."); - this.#destroyQueue(message.guild.id); - }); - - queue.player.on(AudioPlayerStatus.Idle, () => { - if (queue.loop) queue.queue.push(queue.current); - const queueElement = queue.queue.shift(); - if (queueElement === undefined) { - this.#destroyQueue(message.guild.id); - return { content: "Played all tracks leaving the channel.", announce: true }; - } - this.play(message.guild.id, queueElement); - }); - - this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - return "Started playing track!"; - } - - const queue = this.#queue.get(message.guild.id); - - if (queue.voiceChannel !== message.member.voice.channel.id) { - return "You have to be in the same voice channel as the bot to add new tracks."; - } - - queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); - } - - skip(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to skip tracks."; - - const queueElement = queue.queue.shift(); - - if (queueElement === undefined && !queue.loop) { - if (queue.loop) { - this.play(message.guild.id, queueElement || queue.current); - } else { - this.#destroyQueue(message.guild.id); - } - return { content: "Skipped last track. Leaving channel!", announce: true }; - } else { - this.play(message.guild.id, queueElement || queue.current); - return { content: "Skipped track.", announce: true }; - } - } - - stop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to stop the bot."; - - this.#destroyQueue(message.guild.id); - return { content: "Leaving channel.", announce: true }; - } - - shuffle(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to shuffle the queue."; - - queue.queue.shuffle(); - return { content: "Shuffled the Queue.", announce: true }; - } - - getQueue(guildId) { - return this.#queue.get(guildId); - } - - getCurrent(guildId) { - return this.#queue.get(guildId)?.current; - } - - clearQueue(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to clear the queue."; - - queue.queue.clear(); - return { content: "Cleared queue.", announce: true }; - } - - #channelEmpty(channelId) { - return this.#client.channels.cache.get(channelId)?.members.filter((member) => !member.user.bot).size === 0; - } - - troll(message) { - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return; - queue.queue.clear(); - /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ - this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); - } - - toggleLoop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to toggle looping."; - - queue.loop = !queue.loop; - if (queue.loop) { - return { content: "Looping is now enabled.", announce: true }; - } else { - return { content: "Looping is now disabled.", announce: true }; - } - } - - pause(message) { - if (message.member.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "There is nothing playing"; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to pause the track"; - - if (queue.player.state.status == "playing") { - queue.player.pause(); - return { content: "The track has been paused", announce: true }; - } else if (queue.player.state.status == "paused") { - return "The track is already paused"; - } - } - - resume(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to pause"; - - if (queue.player.state.status == "paused") { - queue.player.unpause(); - return { content: "The track has been resumed", announce: true }; - } else if (queue.player.state.status == "playing") { - return "The track is already playing"; - } - } + //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? + //TODO: Add previous function --> Completely rewrite the queue system + //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) + //TODO: Add Spotify support + //TODO: Add Soundcloud support + //TODO: Don't get sued by YouTube + //TODO: Complete rewrite of the player + //BUG: See issue #17 + + #queue = new Map(); + #client; + + constructor(client) { + this.#client = client; + + this.#client.on("voiceStateUpdate", (oldState, newState) => { + const queue = this.getQueue(newState.guild.id); + + if (queue === undefined || oldState.channelId === null) { + return; + } + + if (oldState.id !== this.#client.user.id) { + if (this.#channelEmpty(oldState.channelId)) { + queue.current.channel.send("Leaving channel because it is empty."); + this.#destroyQueue(newState.guild.id); + } + return; + } + if (newState.channelId === undefined) { + queue.current.channel.send("I have been kicked from the channel."); + this.#destroyQueue(newState.guild.id); + } + + if (oldState.channelId !== newState.channelId) { + queue.voiceChannel = newState.channelId; + client.voiceChannel = newState.channelId; + } + }); + } + + #newQueue(guildId) { + this.#queue.set(guildId, { + connection: null, + voiceChannel: null, + player: null, + current: null, + loop: false, + guildId: null, + queue: new ImprovedArray() + }); + } + + #destroyQueue(guildId) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === undefined) return; + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + } + guildInfo.connection.destroy(); + this.#queue.delete(guildId); + } + + async play(guildId, track) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === undefined) return; + guildInfo.current = track; + + const stream = await AudioStream(track.url); + const resource = createAudioResource(stream.stream, { inputType: stream.type }); + + guildInfo.player.play(resource); + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); + } + guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); + } + + async #createEmbed(info, type) { + const embed = new EmbedBuilder() + .setURL(info.url) + .setColor(Colors.Red) + .setTimestamp(new Date()) + .setFooter(this.#client.config.embedFooter(this.#client)); + + if (info.title) { + embed.setTitle(`${type} track ${info.title}`); + } + + if (info.thumbnails) { + const thumbnail = info.thumbnails[info.thumbnails.length - 1]; + if (thumbnail) { + embed.setImage(thumbnail.url); + } + } + + return embed; + } + + async addTrack(message, args) { + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + + let videoName = args.map(e => e.trim()).join(" ").trim(); + + if (videoName === "") return "Please enter the link/name of the track"; + + let url; + if (videoName.startsWith("https") && yt_validate(videoName) === "video") { + url = videoName; + } else { + const yt_infos = await search(args.join(" "), { limit: 10 }); + let currentInfo = 0; + do { + url = yt_infos[currentInfo].url; + currentInfo++; + } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); + } + + let info; + try { + info = (await video_basic_info(url)).video_details; + } catch (err) { } + if (info === undefined) { + if (this.#queue.get(message.guild.id)?.queue.length === 0) return; + let returnValue = this.skip(message); + returnValue.content = "Can't play tracks requiring age verification! Skipping..."; + return returnValue; + } + + if (!this.#queue.has(message.guild.id)) { + this.#newQueue(message.guild.id); + const queue = this.#queue.get(message.guild.id); + const connection = joinVoiceChannel({ + channelId: message.member.voice.channel.id, + guildId: message.guild.id, + adapterCreator: message.guild.voiceAdapterCreator + }); + + const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); + connection.subscribe(player); + + queue.connection = connection; + queue.player = player; + queue.voiceChannel = message.member.voice.channel.id; + this.#client.voiceChannel = message.member.voice.channel.id; + queue.guildId = message.guild.id; + + queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { + try { + await Promise.race([ + entersState(connection, VoiceConnectionStatus.Signalling, 5_000), + entersState(connection, VoiceConnectionStatus.Connecting, 5_000), + ]); + } catch (error) { + this.#destroyQueue(queue.guildId); + return "There was an error connecting to the voice channel."; + } + }); + + queue.player.on("error", (err) => { + message.channel.send("An error occurred while playing the track."); + this.#destroyQueue(message.guild.id); + }); + + queue.player.on(AudioPlayerStatus.Idle, () => { + if (queue.loop) queue.queue.push(queue.current); + const queueElement = queue.queue.shift(); + if (queueElement === undefined) { + this.#destroyQueue(message.guild.id); + return { content: "Played all tracks leaving the channel.", announce: true }; + } + this.play(message.guild.id, queueElement); + }); + + this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + return "Started playing track!"; + } + + const queue = this.#queue.get(message.guild.id); + + if (queue.voiceChannel !== message.member.voice.channel.id) { + return "You have to be in the same voice channel as the bot to add new tracks."; + } + + queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); + } + + skip(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to skip tracks."; + + const queueElement = queue.queue.shift(); + + if (queueElement === undefined && !queue.loop) { + if (queue.loop) { + this.play(message.guild.id, queueElement || queue.current); + } else { + this.#destroyQueue(message.guild.id); + } + return { content: "Skipped last track. Leaving channel!", announce: true }; + } else { + this.play(message.guild.id, queueElement || queue.current); + return { content: "Skipped track.", announce: true }; + } + } + + stop(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to stop the bot."; + + this.#destroyQueue(message.guild.id); + return { content: "Leaving channel.", announce: true }; + } + + shuffle(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to shuffle the queue."; + + queue.queue.shuffle(); + return { content: "Shuffled the Queue.", announce: true }; + } + + getQueue(guildId) { + return this.#queue.get(guildId); + } + + getCurrent(guildId) { + return this.#queue.get(guildId)?.current; + } + + clearQueue(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to clear the queue."; + + queue.queue.clear(); + return { content: "Cleared queue.", announce: true }; + } + + #channelEmpty(channelId) { + return this.#client.channels.cache.get(channelId)?.members.filter((member) => !member.user.bot).size === 0; + } + + troll(message) { + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return; + queue.queue.clear(); + /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ + this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); + } + + toggleLoop(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to toggle looping."; + + queue.loop = !queue.loop; + if (queue.loop) { + return { content: "Looping is now enabled.", announce: true }; + } else { + return { content: "Looping is now disabled.", announce: true }; + } + } + + pause(message) { + if (message.member.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "There is nothing playing"; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to pause the track"; + + if (queue.player.state.status == "playing") { + queue.player.pause(); + return { content: "The track has been paused", announce: true }; + } else if (queue.player.state.status == "paused") { + return "The track is already paused"; + } + } + + resume(message) { + if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); + if (queue === undefined) return "No queue for guild."; + + if (queue.voiceChannel !== message.member.voice.channel.id) + return "You have to be in the same voice channel as the bot to pause"; + + if (queue.player.state.status == "paused") { + queue.player.unpause(); + return { content: "The track has been resumed", announce: true }; + } else if (queue.player.state.status == "playing") { + return "The track is already playing"; + } + } }; async function isAgeRestricted(url) { - try { - (await video_basic_info(url)).video_details; - } catch (err) { - return true; - } - return false; + try { + (await video_basic_info(url)).video_details; + } catch (err) { + return true; + } + return false; } diff --git a/music/player.ts.ignore b/music/player.ts.ignore index d5617bd..8437f24 100644 --- a/music/player.ts.ignore +++ b/music/player.ts.ignore @@ -8,366 +8,366 @@ import { ImprovedArray } from "sussy-util"; import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } from "discord.js"; const playerControls = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId('command:queue') - .setLabel('☰') - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId('play_pause') - .setLabel('׀׀') - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId('command:stop') - .setLabel('◼') - .setStyle(ButtonStyle.Danger), - new ButtonBuilder() - .setCustomId('command:skip') - .setLabel('>>') - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId('support') - .setLabel('Support us!') - .setStyle(ButtonStyle.Secondary), - ); + .addComponents( + new ButtonBuilder() + .setCustomId('command:queue') + .setLabel('☰') + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId('play_pause') + .setLabel('׀׀') + .setStyle(ButtonStyle.Success), + new ButtonBuilder() + .setCustomId('command:stop') + .setLabel('◼') + .setStyle(ButtonStyle.Danger), + new ButtonBuilder() + .setCustomId('command:skip') + .setLabel('>>') + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId('support') + .setLabel('Support us!') + .setStyle(ButtonStyle.Secondary), + ); module.exports = class Player { - //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? - //TODO: Add previous function --> Completely rewrite the queue system - //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) - //TODO: Add Spotify support - //TODO: Add SoundCloud support - //TODO: Don't get sued by YouTube - //TODO: Complete rewrite of the player - //BUG: See issue #17 - - #queue = new Map(); - #client; - - constructor(client: Client) { - this.#client = client; - - this.#client.on("voiceStateUpdate", (oldState, newState) => { - const queue = this.getQueue(newState.guild.id); - - if (queue === void 0 || oldState.channelId === null) { - return; - } - - if (oldState.id !== this.#client.user.id) { - if (this.#channelEmpty(oldState.channelId)) { - queue.current.channel.send("Leaving channel because it is empty."); - this.#destroyQueue(newState.guild.id); - } - return; - } - if (newState.channelId === void 0) { - queue.current.channel.send("I have been kicked from the channel."); - this.#destroyQueue(newState.guild.id); - } - - if (oldState.channelId !== newState.channelId) { - queue.voiceChannel = newState.channelId; - } - }); - } - - #newQueue(guildId: string) { - this.#queue.set(guildId, { - connection: null, - voiceChannel: null, - player: null, - current: null, - loop: false, - guildId: null, - queue: new ImprovedArray() - }); - } - - #destroyQueue(guildId: string) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === void 0) return; - if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); - } - guildInfo.connection.destroy(); - this.#queue.delete(guildId); - } - - async play(guildId: string, track: QueueElement) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === void 0) return; - guildInfo.current = track; - - const streamReturn = await stream(track.url); - const resource = createAudioResource(streamReturn.stream, { inputType: streamReturn.type }); - - guildInfo.player.play(resource); - if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); - } - // @ts-expect-error - guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); - } - - async #createEmbed(info: QueueElement, type: string) { - const embed = new EmbedBuilder() - .setURL(info.url) - .setColor(Colors.Red) - .setTimestamp(new Date()) - // @ts-expect-error - .setFooter(this.#client.config.embedFooter(this.#client)); - - if (info.title) { - embed.setTitle(`${type} track ${info.title}`); - } - - if (info.thumbnails) { - const thumbnail = info.thumbnails[info.thumbnails.length - 1]; - if (thumbnail) { - embed.setImage(thumbnail.url); - } - } - - return embed; - } - - async addTrack(message: Message, args: string[]) { - if (message.member!.voice?.channel === void 0 || message.member!.voice?.channel === null) return "Connect to a Voice Channel"; - - let videoName = args.map(e => e.trim()).join(" ").trim(); - - if (videoName === "") return "Please enter the link/name of the track"; - - let url; - if (videoName.startsWith("https") && yt_validate(videoName) === "video") { - url = videoName; - } else { - const yt_infos = await search(args.join(" "), { limit: 10 }); - let currentInfo = 0; - do { - url = yt_infos[currentInfo].url; - currentInfo++; - } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); - } - - let info; - try { - info = (await video_basic_info(url)).video_details; - } catch (err) { - - } - if (info === void 0) { - if (this.#queue.get(message.guild!.id)?.queue.length === 0) return; - let returnValue = this.skip(message) as CommandReturnWithoutString; - returnValue!.content = "Can't play tracks requiring age verification! Skipping..."; - return returnValue; - } - - if (!this.#queue.has(message.guild!.id)) { - this.#newQueue(message.guild!.id); - const queue = this.#queue.get(message.guild!.id); - const connection = joinVC({ - channelId: message.member!.voice.channel.id, - guildId: message.guild!.id, - adapterCreator: message.guild!.voiceAdapterCreator - }); - - const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); - connection.subscribe(player); - - queue.connection = connection; - queue.player = player; - queue.voiceChannel = message.member!.voice.channel.id; - queue.guildId = message.guild!.id; - - queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { - try { - await Promise.race([ - entersState(connection, VoiceConnectionStatus.Signalling, 5_000), - entersState(connection, VoiceConnectionStatus.Connecting, 5_000), - ]); - } catch (error) { - this.#destroyQueue(queue.guildId); - return "There was an error connecting to the voice channel."; - } - }); - - queue.player.on("error", (err: Error) => { - message.channel.send("An error occurred while playing the track."); - this.#destroyQueue(message.guild!.id); - err; - }); - - queue.player.on(AudioPlayerStatus.Idle, () => { - if (queue.loop) queue.queue.push(queue.current); - const queueElement = queue.queue.shift(); - if (queueElement === void 0) { - this.#destroyQueue(message.guild!.id); - return { content: "Played all tracks leaving the channel.", announce: true }; - } - this.play(message.guild!.id, queueElement); - }); - - // @ts-expect-error // I gotta make a type for this - this.play(message.guild!.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - return "Started playing track!"; - } - - const queue = this.#queue.get(message.guild!.id); - - if (queue.voiceChannel !== message.member!.voice.channel.id) { - return "You have to be in the same voice channel as the bot to add new tracks."; - } - - queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - // @ts-expect-error // idfk, it's getting ignored anyway - return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); - } - - skip(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to skip tracks."; - - const queueElement = queue.queue.shift(); - - if (queueElement === void 0 && !queue.loop) { - if (queue.loop) { - this.play(message.guild!.id, queueElement || queue.current); - } else { - this.#destroyQueue(message.guild!.id); - } - return { content: "Skipped last track. Leaving channel!", announce: true }; - } else { - this.play(message.guild!.id, queueElement || queue.current); - return { content: "Skipped track.", announce: true }; - } - } - - stop(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to stop the bot."; - - this.#destroyQueue(message.guild!.id); - return { content: "Leaving channel.", announce: true }; - } - - shuffle(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to shuffle the queue."; - - queue.queue.shuffle(); - return { content: "Shuffled the Queue.", announce: true }; - } - - getQueue(guildId: string) { - return this.#queue.get(guildId); - } - - getCurrent(guildId: string) { - return this.#queue.get(guildId)?.current; - } - - clearQueue(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0 || queue.queue.length == 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to clear the queue."; - - queue.queue.clear(); - return { content: "Cleared queue.", announce: true }; - } - - #channelEmpty(channelId: string) { - // @ts-expect-error // I gotta make this compatible with DM Channels - return this.#client.channels.cache.get(channelId)?.members.filter((member: GuildMember) => !member.user.bot).size === 0; - } - - troll(message: Message) { - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return; - queue.queue.clear(); - /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ - // @ts-expect-error // I gotta make a type for this - this.play(message.guild!.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); - } - - toggleLoop(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to toggle looping."; - - queue.loop = !queue.loop; - if (queue.loop) { - return { content: "Looping is now enabled.", announce: true }; - } else { - return { content: "Looping is now disabled.", announce: true }; - } - } - - pause(message: Message) { - if (message.member!.voice?.channel === void 0) return "You have to be in the same voice channel as the bot to pause the track"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "There is nothing playing"; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to pause the track"; - - if (queue.player.state.status == "playing") { - queue.player.pause(); - return { content: "The track has been paused", announce: true }; - } else if (queue.player.state.status == "paused") { - return "The track is already paused"; - } - } - - resume(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member!.voice.channel!.id) - return "You have to be in the same voice channel as the bot to pause"; - - if (queue.player.state.status == "paused") { - queue.player.unpause(); - return { content: "The track has been resumed", announce: true }; - } else if (queue.player.state.status == "playing") { - return "The track is already playing"; - } - } + //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? + //TODO: Add previous function --> Completely rewrite the queue system + //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) + //TODO: Add Spotify support + //TODO: Add SoundCloud support + //TODO: Don't get sued by YouTube + //TODO: Complete rewrite of the player + //BUG: See issue #17 + + #queue = new Map(); + #client; + + constructor(client: Client) { + this.#client = client; + + this.#client.on("voiceStateUpdate", (oldState, newState) => { + const queue = this.getQueue(newState.guild.id); + + if (queue === void 0 || oldState.channelId === null) { + return; + } + + if (oldState.id !== this.#client.user.id) { + if (this.#channelEmpty(oldState.channelId)) { + queue.current.channel.send("Leaving channel because it is empty."); + this.#destroyQueue(newState.guild.id); + } + return; + } + if (newState.channelId === void 0) { + queue.current.channel.send("I have been kicked from the channel."); + this.#destroyQueue(newState.guild.id); + } + + if (oldState.channelId !== newState.channelId) { + queue.voiceChannel = newState.channelId; + } + }); + } + + #newQueue(guildId: string) { + this.#queue.set(guildId, { + connection: null, + voiceChannel: null, + player: null, + current: null, + loop: false, + guildId: null, + queue: new ImprovedArray() + }); + } + + #destroyQueue(guildId: string) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === void 0) return; + if (guildInfo.lastNowPlayingMessage !== void 0) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); + } + guildInfo.connection.destroy(); + this.#queue.delete(guildId); + } + + async play(guildId: string, track: QueueElement) { + const guildInfo = this.#queue.get(guildId); + if (guildInfo === void 0) return; + guildInfo.current = track; + + const streamReturn = await stream(track.url); + const resource = createAudioResource(streamReturn.stream, { inputType: streamReturn.type }); + + guildInfo.player.play(resource); + if (guildInfo.lastNowPlayingMessage !== void 0) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); + } + // @ts-expect-error + guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); + } + + async #createEmbed(info: QueueElement, type: string) { + const embed = new EmbedBuilder() + .setURL(info.url) + .setColor(Colors.Red) + .setTimestamp(new Date()) + // @ts-expect-error + .setFooter(this.#client.config.embedFooter(this.#client)); + + if (info.title) { + embed.setTitle(`${type} track ${info.title}`); + } + + if (info.thumbnails) { + const thumbnail = info.thumbnails[info.thumbnails.length - 1]; + if (thumbnail) { + embed.setImage(thumbnail.url); + } + } + + return embed; + } + + async addTrack(message: Message, args: string[]) { + if (message.member!.voice?.channel === void 0 || message.member!.voice?.channel === null) return "Connect to a Voice Channel"; + + let videoName = args.map(e => e.trim()).join(" ").trim(); + + if (videoName === "") return "Please enter the link/name of the track"; + + let url; + if (videoName.startsWith("https") && yt_validate(videoName) === "video") { + url = videoName; + } else { + const yt_infos = await search(args.join(" "), { limit: 10 }); + let currentInfo = 0; + do { + url = yt_infos[currentInfo].url; + currentInfo++; + } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); + } + + let info; + try { + info = (await video_basic_info(url)).video_details; + } catch (err) { + + } + if (info === void 0) { + if (this.#queue.get(message.guild!.id)?.queue.length === 0) return; + let returnValue = this.skip(message) as CommandReturnWithoutString; + returnValue!.content = "Can't play tracks requiring age verification! Skipping..."; + return returnValue; + } + + if (!this.#queue.has(message.guild!.id)) { + this.#newQueue(message.guild!.id); + const queue = this.#queue.get(message.guild!.id); + const connection = joinVC({ + channelId: message.member!.voice.channel.id, + guildId: message.guild!.id, + adapterCreator: message.guild!.voiceAdapterCreator + }); + + const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); + connection.subscribe(player); + + queue.connection = connection; + queue.player = player; + queue.voiceChannel = message.member!.voice.channel.id; + queue.guildId = message.guild!.id; + + queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { + try { + await Promise.race([ + entersState(connection, VoiceConnectionStatus.Signalling, 5_000), + entersState(connection, VoiceConnectionStatus.Connecting, 5_000), + ]); + } catch (error) { + this.#destroyQueue(queue.guildId); + return "There was an error connecting to the voice channel."; + } + }); + + queue.player.on("error", (err: Error) => { + message.channel.send("An error occurred while playing the track."); + this.#destroyQueue(message.guild!.id); + err; + }); + + queue.player.on(AudioPlayerStatus.Idle, () => { + if (queue.loop) queue.queue.push(queue.current); + const queueElement = queue.queue.shift(); + if (queueElement === void 0) { + this.#destroyQueue(message.guild!.id); + return { content: "Played all tracks leaving the channel.", announce: true }; + } + this.play(message.guild!.id, queueElement); + }); + + // @ts-expect-error // I gotta make a type for this + this.play(message.guild!.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + return "Started playing track!"; + } + + const queue = this.#queue.get(message.guild!.id); + + if (queue.voiceChannel !== message.member!.voice.channel.id) { + return "You have to be in the same voice channel as the bot to add new tracks."; + } + + queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + // @ts-expect-error // idfk, it's getting ignored anyway + return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); + } + + skip(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to skip tracks."; + + const queueElement = queue.queue.shift(); + + if (queueElement === void 0 && !queue.loop) { + if (queue.loop) { + this.play(message.guild!.id, queueElement || queue.current); + } else { + this.#destroyQueue(message.guild!.id); + } + return { content: "Skipped last track. Leaving channel!", announce: true }; + } else { + this.play(message.guild!.id, queueElement || queue.current); + return { content: "Skipped track.", announce: true }; + } + } + + stop(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to stop the bot."; + + this.#destroyQueue(message.guild!.id); + return { content: "Leaving channel.", announce: true }; + } + + shuffle(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to shuffle the queue."; + + queue.queue.shuffle(); + return { content: "Shuffled the Queue.", announce: true }; + } + + getQueue(guildId: string) { + return this.#queue.get(guildId); + } + + getCurrent(guildId: string) { + return this.#queue.get(guildId)?.current; + } + + clearQueue(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0 || queue.queue.length == 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to clear the queue."; + + queue.queue.clear(); + return { content: "Cleared queue.", announce: true }; + } + + #channelEmpty(channelId: string) { + // @ts-expect-error // I gotta make this compatible with DM Channels + return this.#client.channels.cache.get(channelId)?.members.filter((member: GuildMember) => !member.user.bot).size === 0; + } + + troll(message: Message) { + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return; + queue.queue.clear(); + /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ + // @ts-expect-error // I gotta make a type for this + this.play(message.guild!.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); + } + + toggleLoop(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to toggle looping."; + + queue.loop = !queue.loop; + if (queue.loop) { + return { content: "Looping is now enabled.", announce: true }; + } else { + return { content: "Looping is now disabled.", announce: true }; + } + } + + pause(message: Message) { + if (message.member!.voice?.channel === void 0) return "You have to be in the same voice channel as the bot to pause the track"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "There is nothing playing"; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to pause the track"; + + if (queue.player.state.status == "playing") { + queue.player.pause(); + return { content: "The track has been paused", announce: true }; + } else if (queue.player.state.status == "paused") { + return "The track is already paused"; + } + } + + resume(message: Message) { + if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild!.id); + if (queue === void 0) return "No queue for guild."; + + if (queue.voiceChannel !== message.member!.voice.channel!.id) + return "You have to be in the same voice channel as the bot to pause"; + + if (queue.player.state.status == "paused") { + queue.player.unpause(); + return { content: "The track has been resumed", announce: true }; + } else if (queue.player.state.status == "playing") { + return "The track is already playing"; + } + } }; async function isAgeRestricted(url: string) { - try { - (await video_basic_info(url)).video_details; - } catch (err) { - return true; - } - return false; + try { + (await video_basic_info(url)).video_details; + } catch (err) { + return true; + } + return false; } type QueueElement = { - url: string; - channel: BaseChannel; - title: string; - duration?: string; - thumbnails: any[]; + url: string; + channel: BaseChannel; + title: string; + duration?: string; + thumbnails: any[]; }; \ No newline at end of file diff --git a/schemas/guild.ts b/schemas/guild.ts index 4b42108..d0ac9e2 100644 --- a/schemas/guild.ts +++ b/schemas/guild.ts @@ -1,31 +1,31 @@ const { Schema, model } = require("mongoose"); const guildSchema = new Schema({ - _id: Schema.Types.ObjectId, - guildId: String, + _id: Schema.Types.ObjectId, + guildId: String, - channels: { - welcome: String, - goodbye: String, - counter: String, + channels: { + welcome: String, + goodbye: String, + counter: String, - allowed: [ - String - ], - }, + allowed: [ + String + ], + }, - counter: { - current: Number, - lastId: String - }, + counter: { + current: Number, + lastId: String + }, - warns: [ - { userId: String, count: Number } - ], + warns: [ + { userId: String, count: Number } + ], - tempBans: [ - { userId: String, endDate: Date } - ] + tempBans: [ + { userId: String, endDate: Date } + ] }); export default model("guild", guildSchema, "guilds"); diff --git a/schemas/user.ts b/schemas/user.ts index 09335c5..946c29b 100644 --- a/schemas/user.ts +++ b/schemas/user.ts @@ -1,21 +1,21 @@ const { Schema, model } = require(`mongoose`); const userSchema = new Schema({ - _id: Schema.Types.ObjectId, - userId: { require: true, type: String }, + _id: Schema.Types.ObjectId, + userId: { require: true, type: String }, - level: { - xp: { type: Number, default: 0 }, - }, + level: { + xp: { type: Number, default: 0 }, + }, - economy: { - wallet: { type: Number, default: 0 }, - bank: { type: Number, default: 0 }, - }, + economy: { + wallet: { type: Number, default: 0 }, + bank: { type: Number, default: 0 }, + }, - jobinfo: { - id: { type: Number, default: 1 }, - } + jobinfo: { + id: { type: Number, default: 1 }, + } }); export default model("user", userSchema, "users"); diff --git a/selectMenus/general/help.ts b/selectMenus/general/help.ts index 2aa9d27..6f8abdb 100644 --- a/selectMenus/general/help.ts +++ b/selectMenus/general/help.ts @@ -1,8 +1,8 @@ import { Component } from "../../types/command"; module.exports = { - run(client, interaction, args, guildData, userData) { - console.info("helpmenu.js", args); - return "This command is currently WIP but I already known that you selected " + args[0] + "! MAGIC!"; - } + run(client, interaction, args, guildData, userData) { + console.info("helpmenu.js", args); + return "This command is currently WIP but I already known that you selected " + args[0] + "! MAGIC!"; + } } as Component; \ No newline at end of file diff --git a/types/client.ts b/types/client.ts index 8a61afb..172520b 100644 --- a/types/client.ts +++ b/types/client.ts @@ -5,20 +5,20 @@ import Player from "../music/player"; import { connection } from "mongoose"; export default interface Client extends DiscordClient { - commands: Collection; - player: Player; - commandCooldowns: Collection>; - config: ClientConfig; - functions?: Function[]; - connection: typeof connection; + commands: Collection; + player: Player; + commandCooldowns: Collection>; + config: ClientConfig; + functions?: Function[]; + connection: typeof connection; } type ClientConfig = { - token: string; - prefix: string; - authors: string[]; - mongoURI: string; - authorsString: string; - version: string; - embedFooter: { text: string }; + token: string; + prefix: string; + authors: string[]; + mongoURI: string; + authorsString: string; + version: string; + embedFooter: { text: string }; } diff --git a/types/command.ts b/types/command.ts index d202795..a47d537 100644 --- a/types/command.ts +++ b/types/command.ts @@ -2,50 +2,50 @@ import { CommandInteraction, ApplicationCommandOption, CacheType, Message, Inter import Client from "./client"; export interface Command { - ignore?: boolean; - name?: string; - aliases?: string[]; - description: string; - options?: ApplicationCommandOption[]; - default_member_permissions?: string; - commandOptions?: CommandOptions; - category?: string; - run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: any, userData: any, isInteraction: boolean) => CommandReturns; + ignore?: boolean; + name?: string; + aliases?: string[]; + description: string; + options?: ApplicationCommandOption[]; + default_member_permissions?: string; + commandOptions?: CommandOptions; + category?: string; + run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: any, userData: any, isInteraction: boolean) => CommandReturns; } interface CommandOptions { - connectedToVC?: boolean; - connectedToSameVC?: boolean; - guildOnly?: boolean; - defaultReturn?: CommandReturn; - cooldown?: number; + connectedToVC?: boolean; + connectedToSameVC?: boolean; + guildOnly?: boolean; + defaultReturn?: CommandReturn; + cooldown?: number; } interface extensionWithoutDM { - announce?: boolean; - success?: boolean; - setCooldown?: Command[]; - disableOriginal?: boolean; - deleteMessage?: boolean | number; - deleteReply?: boolean | number; - disable?: number | boolean; - disableMentions?: boolean; - timeout?: number; + announce?: boolean; + success?: boolean; + setCooldown?: Command[]; + disableOriginal?: boolean; + deleteMessage?: boolean | number; + deleteReply?: boolean | number; + disable?: number | boolean; + disableMentions?: boolean; + timeout?: number; } interface MessageExtensionsWithoutDMMessage extends MessageReplyOptions, extensionWithoutDM { } interface MessageExtensionsMessage extends MessageExtensionsWithoutDMMessage { - DM?: MessageExtensionsWithoutDMMessage; + DM?: MessageExtensionsWithoutDMMessage; } interface MessageExtensionsWithoutDMInteraction extends InteractionReplyOptions, extensionWithoutDM { } interface MessageExtensionsInteraction extends MessageExtensionsWithoutDMInteraction { - DM?: MessageExtensionsWithoutDMInteraction; + DM?: MessageExtensionsWithoutDMInteraction; } diff --git a/www/index.ts b/www/index.ts index 467aeb8..75f8910 100644 --- a/www/index.ts +++ b/www/index.ts @@ -9,13 +9,13 @@ app.use(express.static(`${__dirname}/static/`)); const files = fs.readdirSync(`${__dirname}/routes`); for (const file of files) { - if (!file.endsWith("js")) continue; - const filePath = file.split(".")[0]; - app.use(`/${filePath}`, require(`./routes/${file}`)); + if (!file.endsWith("js")) continue; + const filePath = file.split(".")[0]; + app.use(`/${filePath}`, require(`./routes/${file}`)); } module.exports = { - startServer: (client: Client, port: number, callback: Function) => { - app.listen(port, callback); - } + startServer: (client: Client, port: number, callback: Function) => { + app.listen(port, callback); + } } \ No newline at end of file diff --git a/www/routes/commands.ts b/www/routes/commands.ts index a238851..e1de3e6 100644 --- a/www/routes/commands.ts +++ b/www/routes/commands.ts @@ -7,25 +7,25 @@ import express from "express"; const router = express.Router(); router.get("/allcommands", (req: any, res: any) => { - const commandName = [] as { name: string, description: string }[]; - client.commands.forEach(command => commandName.push({ name: command.name!, description: command.description })); - res.send(JSON.stringify(commandName)); + const commandName = [] as { name: string, description: string }[]; + client.commands.forEach(command => commandName.push({ name: command.name!, description: command.description })); + res.send(JSON.stringify(commandName)); }); router.get("/:cmdname", (req: any, res: any) => { - const cmd = req.params.cmdname; - const command = client.commands.find(cmd1 => cmd1.name === cmd); - if (!command) return res.status(404).send(""); - const clone = deepClone(command) as any; - clone.permissions?.forEach((e: any, i: number) => { - for (const key in permissions) { - // @ts-expect-error - if (BigInt(permissions[key]) != e) - continue; - clone.permissions[i] = key; - } - }); - res.send(JSON.stringify(removeProperty(clone, "default_member_permissions"))); + const cmd = req.params.cmdname; + const command = client.commands.find(cmd1 => cmd1.name === cmd); + if (!command) return res.status(404).send(""); + const clone = deepClone(command) as any; + clone.permissions?.forEach((e: any, i: number) => { + for (const key in permissions) { + // @ts-expect-error + if (BigInt(permissions[key]) != e) + continue; + clone.permissions[i] = key; + } + }); + res.send(JSON.stringify(removeProperty(clone, "default_member_permissions"))); }); module.exports = router; \ No newline at end of file diff --git a/www/routes/logo.ts b/www/routes/logo.ts index bf7a66a..e8a1570 100644 --- a/www/routes/logo.ts +++ b/www/routes/logo.ts @@ -5,11 +5,11 @@ const path = require("path"); const router = express.Router(); router.get("/", async (req: any, res: any) => { - const image = await loadImage(path.resolve(__dirname, "../assets/SUS-Bot-logos_white.png")); - const canvas = createCanvas(image.width, image.height); - const ctx = canvas.getContext("2d"); - ctx.drawImage(image, 0, 0, image.width, image.height); - res.send(canvas.toDataURL()); + const image = await loadImage(path.resolve(__dirname, "../assets/SUS-Bot-logos_white.png")); + const canvas = createCanvas(image.width, image.height); + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, 0, 0, image.width, image.height); + res.send(canvas.toDataURL()); }); module.exports = router; \ No newline at end of file diff --git a/www/static/commands/index.ts b/www/static/commands/index.ts index daf70a6..c77e711 100644 --- a/www/static/commands/index.ts +++ b/www/static/commands/index.ts @@ -2,24 +2,24 @@ axios.get('../logo').then(e => document.querySelector("#logo").src = e.data).catch(e => console.log(e)); // @ts-expect-error axios.get(`${window.location.href}/allcommands`).then(e => { - const commands = e.data; - const content = document.querySelector(".content"); - commands.forEach((cmd: any) => { - const command = document.createElement("a"); - command.setAttribute("id", cmd.name); - command.href = `${window.location.href}/` + cmd.name; - command.classList.add("command"); - const nameSpan = document.createElement("span"); - nameSpan.id = "name" + cmd.name; - nameSpan.innerText = cmd.name; - const descriptionSpan = document.createElement("span"); - descriptionSpan.id = "description" + cmd.name; - descriptionSpan.innerText = cmd.description; - command.appendChild(nameSpan); - command.appendChild(descriptionSpan); - const line = document.createElement("span"); - line.classList.add("line"); - content!.appendChild(command); - content!.appendChild(line); - }); + const commands = e.data; + const content = document.querySelector(".content"); + commands.forEach((cmd: any) => { + const command = document.createElement("a"); + command.setAttribute("id", cmd.name); + command.href = `${window.location.href}/` + cmd.name; + command.classList.add("command"); + const nameSpan = document.createElement("span"); + nameSpan.id = "name" + cmd.name; + nameSpan.innerText = cmd.name; + const descriptionSpan = document.createElement("span"); + descriptionSpan.id = "description" + cmd.name; + descriptionSpan.innerText = cmd.description; + command.appendChild(nameSpan); + command.appendChild(descriptionSpan); + const line = document.createElement("span"); + line.classList.add("line"); + content!.appendChild(command); + content!.appendChild(line); + }); }).catch((e: Error) => console.log(e)); \ No newline at end of file From 2469a462182e6dd5781e572f5299a82314bb3e50 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 2 Feb 2023 13:09:02 +0100 Subject: [PATCH 14/28] added lint rules --- .eslintrc.js | 56 -------------------------------------------------- .eslintrc.json | 48 +++++++++++++++++++++++++++++++++++++++++++ package.json | 7 ++++++- 3 files changed, 54 insertions(+), 57 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .eslintrc.json diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 5f0fc75..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -👋 Hi! This file was autogenerated by tslint-to-eslint-config. -https://github.com/typescript-eslint/tslint-to-eslint-config - -It represents the closest reasonable ESLint configuration to this -project's original TSLint configuration. - -We recommend eventually switching this configuration to extend from -the recommended rulesets in typescript-eslint. -https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md - -Happy linting! 💖 -*/ -module.exports = { - "env": { - "browser": true, - "es6": true - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "root": true, - "rules": { - "@typescript-eslint/member-delimiter-style": [ - "warn", - { - "multiline": { - "delimiter": "semi", - "requireLast": true - }, - "singleline": { - "delimiter": "semi", - "requireLast": false - } - } - ], - "@typescript-eslint/naming-convention": "warn", - "@typescript-eslint/no-unused-expressions": "warn", - "@typescript-eslint/semi": [ - "warn", - "always" - ], - "eqeqeq": [ - "warn", - "always" - ], - "no-redeclare": "warn", - "no-unused-expressions": "off", - "semi": "off" - } -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..5705507 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,48 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "overrides": [], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "@typescript-eslint/no-var-requires": "warn", + "indent": [ + "error", + "tab", + { + "SwitchCase": 1 + } + ], + "no-empty": [ + "error", + { + "allowEmptyCatch": true + } + ], + "@typescript-eslint/no-empty-function": "off", + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/package.json b/package.json index 4067ffe..fb09d96 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,10 @@ "mongoose": "^6.7.5", "play-dl": "^1.9.6", "sussy-util": "^1.9.0-dev.0.0.4" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.50.0", + "@typescript-eslint/parser": "^5.50.0", + "eslint": "^8.33.0" } -} \ No newline at end of file +} From 17c49940a539fc86227ba2e16e898bfcbe63d5ba Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Sun, 5 Feb 2023 21:55:22 +0100 Subject: [PATCH 15/28] fixed ALMOST every warning --- .eslintrc.json | 21 +- .gitignore | 3 +- buttons/economy/resetBalance.ts | 2 +- buttons/economy/resetLevel.ts | 4 +- buttons/economy/search.ts | 4 +- buttons/general/support.ts | 20 +- commands/economy/beg.ts | 87 ++--- commands/economy/bet.ts | 4 +- commands/economy/deposit.ts | 2 +- commands/economy/job.ts | 6 +- commands/economy/level.ts | 3 +- commands/economy/resetBalance.ts | 2 +- commands/economy/resetLevel.ts | 4 +- commands/economy/search.ts | 5 +- commands/economy/withdraw.ts | 3 +- commands/economy/work.ts | 8 +- commands/games/coinflip.ts | 8 +- commands/games/numberguess.ts | 6 +- commands/general/help.ts | 20 +- commands/general/info.ts | 5 +- commands/general/invite.ts | 2 +- commands/general/inviteBot.ts | 1 - commands/general/serverinfo.ts | 15 +- commands/general/userinfo.ts | 10 +- commands/moderation/clear.ts | 34 +- commands/moderation/lock.ts | 11 +- commands/moderation/nickname.ts | 12 +- commands/moderation/prepare.ts | 14 +- commands/moderation/set-counter-channel.ts | 6 +- commands/moderation/set-goodbye-channel.ts | 4 +- commands/moderation/set-welcome-channel.ts | 4 +- commands/moderation/slowmode.ts | 3 +- commands/moderation/tempban.ts | 2 +- commands/moderation/unban.ts | 15 +- commands/moderation/unlock.ts | 9 +- commands/music/nowPlaying.ts | 6 +- commands/music/play.ts | 5 +- commands/music/queue.ts | 6 +- commands/music/troll.ts | 6 +- commands/testcommands/ping.ts | 6 +- commands/testcommands/playtest.ts | 2 +- enums/permissionBitField.ts | 2 +- enums/permissionStrings.ts | 2 +- events/discord/guildCreate.ts | 4 +- events/discord/guildDelete.ts | 4 +- events/discord/guildMemberAdd.ts | 4 +- events/discord/guildMemberRemove.ts | 2 +- events/discord/interactionCreate.ts | 5 +- events/discord/messageCreate.ts | 8 +- events/discord/ready.ts | 2 +- events/mongodb/connected.ts | 2 +- events/mongodb/connecting.ts | 4 +- events/mongodb/disconnected.ts | 4 +- events/mongodb/err.ts | 2 +- functions/addGuildDocument.ts | 3 +- functions/addUserDocument.ts | 2 +- functions/checkChannelID.ts | 11 +- functions/convertTime.ts | 18 +- functions/counter.ts | 12 +- functions/executeCommand.ts | 136 +++++--- functions/fetchDataFromSave.ts | 4 +- functions/formatCommandReturn.ts | 29 -- functions/getChannelFromMention.ts | 2 +- functions/getFiles.ts | 18 +- functions/getGuildData.ts | 5 +- functions/getUserData.ts | 5 +- functions/replaceUser.ts | 4 +- functions/sendMessage.ts | 7 +- functions/shuffle.ts | 6 +- index.ts | 22 +- logTime.ts | 17 + music/player.js | 354 --------------------- music/{player.ts.ignore => player.ts} | 118 ++++--- schemas/user.ts | 2 +- selectMenus/general/help.ts | 2 +- tslint-to-eslint-config.log | 4 - tslint.json | 13 - types/client.ts | 7 +- types/command.ts | 3 +- types/data.ts | 5 + www/index.ts | 4 +- 81 files changed, 501 insertions(+), 747 deletions(-) delete mode 100644 functions/formatCommandReturn.ts create mode 100644 logTime.ts delete mode 100644 music/player.js rename music/{player.ts.ignore => player.ts} (75%) delete mode 100644 tslint-to-eslint-config.log delete mode 100644 tslint.json create mode 100644 types/data.ts diff --git a/.eslintrc.json b/.eslintrc.json index 5705507..12a3a21 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,7 +17,22 @@ "@typescript-eslint" ], "rules": { - "@typescript-eslint/no-var-requires": "warn", + "@typescript-eslint/no-extra-semi": "warn", + "@typescript-eslint/no-non-null-asserted-optional-chain": "warn", + "prefer-const": "warn", + "@typescript-eslint/ban-ts-comment": "warn", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + "vars": "all", + "args": "after-used", + "ignoreRestSiblings": false, + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/no-var-requires": "off", + "no-constant-condition": "warn", "indent": [ "error", "tab", @@ -37,11 +52,11 @@ "windows" ], "quotes": [ - "error", + "warn", "double" ], "semi": [ - "error", + "warn", "always" ] } diff --git a/.gitignore b/.gitignore index 7d46057..aa4ebe2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ node_modules package-lock.json .vscode logs/* -!**/.gitkeep \ No newline at end of file +!**/.gitkeep +Times.json \ No newline at end of file diff --git a/buttons/economy/resetBalance.ts b/buttons/economy/resetBalance.ts index fa36cca..4199621 100644 --- a/buttons/economy/resetBalance.ts +++ b/buttons/economy/resetBalance.ts @@ -6,7 +6,7 @@ module.exports = { run(_client, _interaction, _args, _guildData, userData) { userData.economy.wallet = 0; userData.economy.bank = 0; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { err; data; }); + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (_err: Error, _data: unknown) => { }); return { content: "Your balance has been reset!", disableOriginal: true }; } } as Component; \ No newline at end of file diff --git a/buttons/economy/resetLevel.ts b/buttons/economy/resetLevel.ts index a689f02..cb34ddc 100644 --- a/buttons/economy/resetLevel.ts +++ b/buttons/economy/resetLevel.ts @@ -1,11 +1,11 @@ import { Component } from "../../types/command"; -const userList = require("../../schemas/user"); +import userList from "../../schemas/user"; module.exports = { run(_client, _interaction, _args, _guildData, userData) { userData.level.xp = 0; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (_err: Error, _data: unknown) => { }); return { content: "Your level has been reset!", disableOriginal: true }; } } as Component; \ No newline at end of file diff --git a/buttons/economy/search.ts b/buttons/economy/search.ts index f9c893b..9aad375 100644 --- a/buttons/economy/search.ts +++ b/buttons/economy/search.ts @@ -12,9 +12,9 @@ module.exports = { const amount = Random.randomInt(900, 1600); const current = userData.economy; current.wallet += amount; - userList.findByIdAndUpdate(userData._id, { economy: current }, (err: Error, data: any) => { err; data; }); + userList.findByIdAndUpdate(userData._id, { economy: current }, (_err: Error, _data: unknown) => { }); userData.level.xp += 2; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { err; data; }); + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (_err: Error, _data: unknown) => { }); return { content: `You found ${amount} gold in the ${args[0]}.`, disableOriginal: true, success: ["command:search", this] }; } } as Component; \ No newline at end of file diff --git a/buttons/general/support.ts b/buttons/general/support.ts index 7c20f91..fa78a40 100644 --- a/buttons/general/support.ts +++ b/buttons/general/support.ts @@ -7,22 +7,22 @@ module.exports = { const choice = new ActionRowBuilder() .addComponents( new ButtonBuilder() - .setLabel('GitHub') + .setLabel("GitHub") .setStyle(ButtonStyle.Link) - .setURL('https://github.com/plastik_flasche/SUS-Bot'), + .setURL("https://github.com/plastik-flasche/SUS-Bot"), new ButtonBuilder() - .setLabel('Patreon') + .setLabel("Patreon") .setStyle(ButtonStyle.Link) - .setURL('https://patreon.com/stupid-useless-patreon'), + .setURL("https://patreon.com/stupid-useless-patreon"), new ButtonBuilder() - .setLabel('PayPal') + .setLabel("PayPal") .setStyle(ButtonStyle.Link) - .setURL('https://paypal.me/stupiduselesspaypal'), + .setURL("https://paypal.me/stupiduselesspaypal"), // new ButtonBuilder() - // .setLabel('Crypto') - // .setStyle('LINK') - // .setURL('') + // .setLabel("Crypto") + // .setStyle("LINK") + // .setURL("") ); - return { content: 'If you can code, help us out on our Github, if not, maybe buy us some more processing power!', components: [choice] }; + return { content: "If you can code, help us out on our Github, if not, maybe buy us some more processing power!", components: [choice] }; } } as Component; diff --git a/commands/economy/beg.ts b/commands/economy/beg.ts index c4fd65a..0b261ec 100644 --- a/commands/economy/beg.ts +++ b/commands/economy/beg.ts @@ -1,47 +1,52 @@ -// import { Command } from "../../types/command"; +import { Command } from "../../types/command"; -// import userList from "../../schemas/user"; -// import messages from "../../resources/messages.json"; +import userList from "../../schemas/user"; +import messages from "../../resources/messages.json"; +import { UserData } from "../../types/data"; -// module.exports = { -// ignore: true, // the messages is kinda broken -// //TODO: fix the messages +module.exports = { + ignore: true, // the messages is kinda broken + //TODO: fix the messages -// description: "Beg to earn money", -// cooldown: 60, + description: "Beg to earn money", + cooldown: 60, -// run(_client, message, _args, _guildData, userData, _isSlashCommand) { -// if (userData.economy?.wallet < 200) -// return "Not enough money to risk on losing"; -// const earned = Math.round(Math.random() * 400) - 200; -// userData.economy.wallet += earned; -// userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { -// if (err) console.error(err); -// if (!data) return "Error: User not found."; -// }); -// userData.level.xp += 2; -// userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { -// if (err) console.error(err); -// if (!data) return "Error: User not found."; -// }); -// if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { -// message.channel!.send(`<@${userData.userId}>` + " just levelled up!") -// } + run(_client, message, _args, _guildData, userData, _isSlashCommand) { + if (userData.economy?.wallet < 200) + return "Not enough money to risk on losing"; + const earned = Math.round(Math.random() * 400) - 200; + userData.economy.wallet += earned; + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: UserData) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + userData.level.xp += 2; + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: UserData) => { + if (err) console.error(err); + if (!data) return "Error: User not found."; + }); + if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { + message.channel?.send(`<@${userData.userId}>` + " just levelled up!"); + } -// let valueRange = Math.ceil(Math.abs(earned / 100)); -// if (earned < 0) valueRange *= -1; + let valueRange = Math.ceil(Math.abs(earned / 100)); + if (earned < 0) valueRange *= -1; -// switch (valueRange) { -// case -2: -// return messages.beg.veryBad.replace("{amount}", Math.abs(earned)); -// case -1: -// return messages.beg.bad.replace("{amount}", Math.abs(earned)); -// case 0: -// return messages.beg.neutral; -// case 1: -// return messages.beg.good.replace("{amount}", earned); -// case 2: -// return messages.beg.veryGood.replace("{amount}", earned); -// } -// } -// } as Command; \ No newline at end of file + switch (valueRange) { + case -2: + return pickRandomAndReplace(messages.beg.veryBad, Math.abs(earned)); + case -1: + return pickRandomAndReplace(messages.beg.bad, Math.abs(earned)); + case 0: + return pickRandomAndReplace(messages.beg.neutral, 0); + case 1: + return pickRandomAndReplace(messages.beg.good, earned); + case 2: + return pickRandomAndReplace(messages.beg.veryGood, earned); + } + } +} as Command; + +function pickRandomAndReplace(messages: string[], replace: number) { + return messages[Math.floor(Math.random() * messages.length)].replace("{amount}", "" + replace); +} \ No newline at end of file diff --git a/commands/economy/bet.ts b/commands/economy/bet.ts index ad0da41..c69d103 100644 --- a/commands/economy/bet.ts +++ b/commands/economy/bet.ts @@ -12,7 +12,7 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Casino") - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)); if (!(IsSomething.isNumber(args[0]))) { @@ -58,7 +58,7 @@ module.exports = { ); break; } - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/economy/deposit.ts b/commands/economy/deposit.ts index 3ed339c..7746193 100644 --- a/commands/economy/deposit.ts +++ b/commands/economy/deposit.ts @@ -35,7 +35,7 @@ module.exports = { moneys = +args[0]; } - users.findByIdAndUpdate(userInfo._id, { economy: current }, (err: Error, data: any) => { + users.findByIdAndUpdate(userInfo._id, { economy: current }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/economy/job.ts b/commands/economy/job.ts index f99a8ea..54f42dd 100644 --- a/commands/economy/job.ts +++ b/commands/economy/job.ts @@ -17,11 +17,11 @@ module.exports = { }], run(client, _message, args, _guildData, userData) { - if (args[0] === void 0) { + if (args[0] === undefined) { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Jobs panel") - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)) .addFields( { @@ -78,7 +78,7 @@ module.exports = { } userData.jobinfo.id = args[0]; - userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: any) => { + userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/economy/level.ts b/commands/economy/level.ts index ab30f80..bb80824 100644 --- a/commands/economy/level.ts +++ b/commands/economy/level.ts @@ -1,6 +1,5 @@ import { Command } from "../../types/command"; -const { IsSomething } = require("sussy-util"); const { EmbedBuilder } = require("discord.js"); module.exports = { description: "Shows the level of your account", @@ -10,7 +9,7 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Level panel") - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)); embed.addFields( diff --git a/commands/economy/resetBalance.ts b/commands/economy/resetBalance.ts index dc3bffb..87ce2fb 100644 --- a/commands/economy/resetBalance.ts +++ b/commands/economy/resetBalance.ts @@ -28,7 +28,7 @@ module.exports = { const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() - .setCustomId(`resetBalance`) + .setCustomId("resetBalance") .setLabel("Confirm") .setStyle(ButtonStyle.Danger), ); diff --git a/commands/economy/resetLevel.ts b/commands/economy/resetLevel.ts index b94a0c1..eb21774 100644 --- a/commands/economy/resetLevel.ts +++ b/commands/economy/resetLevel.ts @@ -11,7 +11,7 @@ module.exports = { .setTitle("Reset Level") .setDescription("Are you sure you want to reset your level?") .setColor(Colors.Red) - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)); if (isInteraction) { @@ -28,7 +28,7 @@ module.exports = { const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() - .setCustomId(`resetLevel`) + .setCustomId("resetLevel") .setLabel("Confirm") .setStyle(ButtonStyle.Danger), ); diff --git a/commands/economy/search.ts b/commands/economy/search.ts index 7e74538..1760d60 100644 --- a/commands/economy/search.ts +++ b/commands/economy/search.ts @@ -1,8 +1,7 @@ import { Command } from "../../types/command"; const { StringUtil } = require("sussy-util"); -const { EmbedBuilder, Colors, ActionRowBuilder, StringSelectMenuBuilder, SelectMenuOptionBuilder, ButtonStyle, ButtonBuilder } = require("discord.js"); -const userList = require("../../schemas/user"); +const { EmbedBuilder, Colors, ActionRowBuilder, ButtonStyle, ButtonBuilder } = require("discord.js"); module.exports = { description: "Search in a few places for money.", @@ -129,7 +128,7 @@ module.exports = { "aquarium", "circus"]; - const actionRow = new ActionRowBuilder() + const actionRow = new ActionRowBuilder(); const embed = new EmbedBuilder(true) .setTitle("Search") diff --git a/commands/economy/withdraw.ts b/commands/economy/withdraw.ts index 10a1ee5..14a619f 100644 --- a/commands/economy/withdraw.ts +++ b/commands/economy/withdraw.ts @@ -1,5 +1,6 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; +import { UserData } from "../../types/data"; const { IsSomething } = require("sussy-util"); const userList = require("../../schemas/user"); @@ -19,7 +20,7 @@ module.exports = { if (amount > userData.economy.bank) amount = userData.economy.bank; userData.economy.bank -= +amount; userData.economy.wallet += +amount; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: UserData) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/economy/work.ts b/commands/economy/work.ts index 1ac2cc2..154e859 100644 --- a/commands/economy/work.ts +++ b/commands/economy/work.ts @@ -19,19 +19,19 @@ module.exports = { run(_client, message, _args, _guildData, userData, _isSlashCommand) { if (userData.economy) { - let earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); + const earned = Math.round(Math.random() * (jobs[userData.jobinfo.id - 1].salary)) + Math.floor(jobs[userData.jobinfo.id - 1].salary / 3); userData.economy.wallet += earned; - userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: any) => { + userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); userData.level.xp += 5; - userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: any) => { + userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); if (!(Math.floor(userData.level.xp / 50) === (Math.floor((userData.level.xp - 5) / 50)))) { - message!.channel!.send(`<@${userData.userId}>` + " just levelled up!") + message.channel?.send(`<@${userData.userId}>` + " just levelled up!"); } return { content: "Congratulations! You earned " + earned + " gold as a " + jobs[userData.jobinfo.id - 1].jobname + ". \nNow you have: " + userData.economy.wallet + "!", setCooldown: [this] }; } diff --git a/commands/games/coinflip.ts b/commands/games/coinflip.ts index 5a600dd..81f6b32 100644 --- a/commands/games/coinflip.ts +++ b/commands/games/coinflip.ts @@ -3,7 +3,7 @@ import { ApplicationCommandOptionType } from "discord.js"; module.exports = { aliases: ["flip", "coin"], - description: 'flips a coin', + description: "flips a coin", options: [{ name: "headsTails", type: ApplicationCommandOptionType.String, @@ -13,11 +13,11 @@ module.exports = { run(_client, message, args, _guildData, _userData, _isSlashCommand) { const coinArray = ["heads", "tails"]; - let numberThrow = Math.floor(Math.random() * 2); - if (!(args[0] === `heads`) && !(args[0] === 'tails')) { + const numberThrow = Math.floor(Math.random() * 2); + if (!(args[0] === "heads") && !(args[0] === "tails")) { return coinArray[numberThrow]; } - message!.channel!.send(coinArray[numberThrow]); + message.channel?.send(coinArray[numberThrow]); if (args[0] === coinArray[numberThrow]) { return "You are victorious!"; } diff --git a/commands/games/numberguess.ts b/commands/games/numberguess.ts index fcc7a19..e1e1376 100644 --- a/commands/games/numberguess.ts +++ b/commands/games/numberguess.ts @@ -21,17 +21,17 @@ module.exports = { ], run(_client, message, args, _guildData, _userData, _isSlashCommand) { - if (args[0] === void 0 || args[0] === `` || args[1] === void 0 || args[1] === ``) { + if (args[0] === undefined || args[0] === "" || args[1] === undefined || args[1] === "") { return "Please specify two numbers"; } if (!(IsSomething.isNumber(args[0])) || !(IsSomething.isNumber(args[1]))) { return "Both parameters need to be numbers"; } if (args[1] > args[0]) { - return "First number needs to be larger than the second" + return "First number needs to be larger than the second"; } const number = Math.round(Math.random() * +args[0] - 1) + 1; - message!.channel!.send("Number was generated! The number is: " + number); + message.channel?.send("Number was generated! The number is: " + number); if (number === +(args[1])) { return "Your number is correct!"; diff --git a/commands/general/help.ts b/commands/general/help.ts index 5e8d70f..fa03d76 100644 --- a/commands/general/help.ts +++ b/commands/general/help.ts @@ -28,25 +28,25 @@ module.exports = { const embed = new EmbedBuilder() .setTimestamp(new Date()) .setTitle("Help panel") - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)); - if (commandName === void 0 || commandName.length === 0) { + if (commandName === undefined || commandName.length === 0) { embed .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); - fs.readdirSync(`${__dirname}/../`).forEach((d: any) => { + fs.readdirSync(`${__dirname}/../`).forEach((d: unknown) => { embed.addFields({ name: StringUtil.capitalize(d), value: "Type `" + client.config.prefix + "help " + d + "` to see more information", - }) + }); menu.addOptions({ label: StringUtil.capitalize(d), value: d }); - });; + }); } else { const cmd = client.commands.get(`command:${commandName}`) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); - if (cmd === void 0) { + if (cmd === undefined) { return "No command found for: `" + commandName + "`"; } @@ -69,13 +69,15 @@ module.exports = { inline: true }, { - name: cmd.aliases?.length! > 1 ? "Aliases" : "Alias", - value: cmd.aliases?.length! > 0 ? cmd.aliases!.join(", ") : "None", + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + name: cmd.aliases!.length > 1 ? "Aliases" : "Alias", + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + value: cmd.aliases!.length > 0 ? cmd.aliases?.join(", ") : "None", inline: true }, { name: "Cooldown", - // @ts-expect-error + // @ts-expect-error // I'm checking if it exists, so it should be fine value: cmd.commandOptions?.defaultReturn?.cooldown ? `${cmd.cooldown}seconds` : "None", inline: true } diff --git a/commands/general/info.ts b/commands/general/info.ts index 5af07a4..613a0f6 100644 --- a/commands/general/info.ts +++ b/commands/general/info.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; const { EmbedBuilder, version: discordjsVersion, Colors } = require("discord.js"); const ms = require("@parade/pretty-ms"); @@ -20,12 +19,12 @@ module.exports = { { name: "Discord.js", value: `${discordjsVersion}`, inline: true }, { name: "Guild Count", value: `${client.guilds.cache.size} guilds`, inline: true }, { name: "User Count", value: `${client.users.cache.size} users`, inline: true }, - { name: "Commands", value: `${client.commands.filter(e => e.name!.startsWith("command:") && !e.ignore).size} commands`, inline: true }, + { name: "Commands", value: `${client.commands.filter(e => e.name?.startsWith("command:") && !e.ignore).size} commands`, inline: true }, { name: "Memory", value: `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB RSS\n${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2)} MB Heap`, inline: true }, { name: "Cached Data", value: `${client.users.cache.size} users\n${client.emojis.cache.size} emojis`, inline: true }, { name: "Node", value: `${process.version} on ${process.platform} ${process.arch}`, inline: true } ) - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)) .setTimestamp(new Date()) ] diff --git a/commands/general/invite.ts b/commands/general/invite.ts index 51d86d7..56b3a2d 100644 --- a/commands/general/invite.ts +++ b/commands/general/invite.ts @@ -8,7 +8,7 @@ module.exports = { async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // It can't even get to this point if it's not a guild - const invite = await message.channel!.createInvite({ unique: true, temporary: true }); + const invite = await message.channel.createInvite({ unique: true, temporary: true }); return "https://discord.gg/" + invite.code; } } as Command; diff --git a/commands/general/inviteBot.ts b/commands/general/inviteBot.ts index a043f7e..c56bad4 100644 --- a/commands/general/inviteBot.ts +++ b/commands/general/inviteBot.ts @@ -1,5 +1,4 @@ import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Sends the invite link of the bot", diff --git a/commands/general/serverinfo.ts b/commands/general/serverinfo.ts index 5efd158..eba4838 100644 --- a/commands/general/serverinfo.ts +++ b/commands/general/serverinfo.ts @@ -5,15 +5,20 @@ const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { description: "Shows information about the server", + commandOptions: { + onlyInGuilds: true + }, + async run(_client, message, _args, _guildData, _userData, _isSlashCommand) { + if (message.guild === null) throw new Error("Something went catastrophically wrong."); const sEmbed = new EmbedBuilder() .setColor(Colors.Red) .setTitle("Server Info") - .setThumbnail(message.guild!.iconURL()) - .setAuthor({ name: `${message.guild!.name} Info`, iconUrl: message.guild!.iconURL() }) - .addFields({ name: "***Guild Name:***", value: `${message.guild!.name}`, inline: true }, - { name: "***Guild Owner:***", value: `<@!${message.guild!.ownerId}>`, inline: true }, - { name: "***Member Count:***", value: `${message.guild!.memberCount}`, inline: true }) + .setThumbnail(message.guild.iconURL()) + .setAuthor({ name: `${message.guild.name} Info`, iconUrl: message.guild.iconURL() }) + .addFields({ name: "***Guild Name:***", value: `${message.guild.name}`, inline: true }, + { name: "***Guild Owner:***", value: `<@!${message.guild.ownerId}>`, inline: true }, + { name: "***Member Count:***", value: `${message.guild.memberCount}`, inline: true }) .setTimestamp(new Date()); return { embeds: [sEmbed] }; diff --git a/commands/general/userinfo.ts b/commands/general/userinfo.ts index 5ffb5aa..52e127e 100644 --- a/commands/general/userinfo.ts +++ b/commands/general/userinfo.ts @@ -1,17 +1,17 @@ import { Command } from "../../types/command"; -const { EmbedBuilder, Colors } = require('discord.js'); +const { EmbedBuilder, Colors } = require("discord.js"); module.exports = { description: "Displays information about the current user.", run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // yes, it does exist! - const user = message.mentions!.users.first() || client.users.cache.get(args[0]) || message.author; + const user = message.mentions.users.first() || client.users.cache.get(args[0]) || message.author; return { embeds: [new EmbedBuilder() - .setTitle("**Userinfo**") + .setTitle("**User info**") .setColor(Colors.Red) .setThumbnail(user.displayAvatarURL()) .addFields( @@ -22,10 +22,10 @@ module.exports = { { name: "Verified", value: user.verified ? "Yes" : "No", inline: true }, { name: "Created", value: user.createdAt.toDateString(), inline: true }, // @ts-expect-error // WTF is this error? - { name: "Joined", value: new Date(message.guild.members.cache.get(user.id)!.joinedTimestamp).toDateString(), inline: true }, + { name: "Joined", value: new Date(message.guild.members.cache.get(user.id).joinedTimestamp).toDateString(), inline: true }, ) .setTimestamp(new Date()) - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)) ] }; diff --git a/commands/moderation/clear.ts b/commands/moderation/clear.ts index d351df9..b782d01 100644 --- a/commands/moderation/clear.ts +++ b/commands/moderation/clear.ts @@ -19,20 +19,25 @@ module.exports = { async run(_client, message, args, _guildData, _userData, isSlashCommand) { const amount = parseInt(args[0]); + if (message.channel === undefined) throw new Error("Channel is undefined"); + if (message.channel === null) throw new Error("Channel is null"); + if (!message.channel) throw new Error("Channel is falsy"); if (args[0] === "all") { clearAllMessages(message, isSlashCommand).then(deletedMessagesCount => { + if (message.channel === null) throw new Error("Channel is null"); if (isSlashCommand) // @ts-expect-error // look at the FIXME below - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); else - message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); }).catch((err: string) => { + if (message.channel === null) throw new Error("Channel is null"); if (isSlashCommand) // @ts-expect-error // look at the FIXME below message.followUp(err); else - message.channel!.send(err); + message.channel.send(err); }); return null; @@ -42,17 +47,19 @@ module.exports = { clearMessages(message, amount, isSlashCommand).then(deletedMessagesCount => { // FIXME: isSlashCommand is kinda unnecessary here when working with TypeScript cause we can check if message is a CommandInteraction + if (message.channel === null) throw new Error("Channel is null"); if (isSlashCommand) // @ts-expect-error // look at the FIXME above - message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + message.followUp(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); else - message.channel!.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel!.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); + message.channel.send(`Deleted ${deletedMessagesCount} messages from <#${message.channel.id}>. Please keep in mind, I can't delete messages older than two weeks!`).then(msg => setTimeout(() => msg.delete(), 5000)); }).catch(err => { + if (message.channel === null) throw new Error("Channel is null"); if (isSlashCommand) // @ts-expect-error // look at the FIXME above message.followUp(err); else - message.channel!.send(err); + message.channel.send(err); }); return null; @@ -60,14 +67,15 @@ module.exports = { } as Command; function clearMessages(message: Message | CommandInteraction, amount: number, isSlashCommand = false) { + // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { let deletedMessagesCount = isSlashCommand ? 0 : -1; while (deletedMessagesCount < amount) { const deleteThisTime = Math.min(...[100, amount - deletedMessagesCount]); // @ts-expect-error // I just can't be bothered to fix this - const deletedMessages = await message.channel!.bulkDelete(deleteThisTime, true) - .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === void 0 || deletedMessages.size === 0) break; + const deletedMessages = await message.channel.bulkDelete(deleteThisTime, true) + .catch((_err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === undefined || deletedMessages.size === 0) break; deletedMessagesCount += deletedMessages.size; } resolve(deletedMessagesCount); @@ -75,13 +83,15 @@ function clearMessages(message: Message | CommandInteraction, amount: number, is } function clearAllMessages(message: Message | CommandInteraction, isSlashCommand = false) { + // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { let deletedMessagesCount = isSlashCommand ? 0 : -1; + // eslint-disable-next-line no-constant-condition while (true) { // @ts-expect-error // I just can't be bothered to fix this - const deletedMessages = await message.channel!.bulkDelete(100, true) - .catch((err: Error) => reject("Cannot delete messages older than two weeks.")); - if (deletedMessages === void 0 || deletedMessages.size === 0) break; + const deletedMessages = await message.channel.bulkDelete(100, true) + .catch((_err: Error) => reject("Cannot delete messages older than two weeks.")); + if (deletedMessages === undefined || deletedMessages.size === 0) break; deletedMessagesCount += deletedMessages.size; } resolve(deletedMessagesCount); diff --git a/commands/moderation/lock.ts b/commands/moderation/lock.ts index d225b77..ff26e5f 100644 --- a/commands/moderation/lock.ts +++ b/commands/moderation/lock.ts @@ -21,22 +21,23 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; - if (!channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) + if (message.guild === null) throw new Error("Guild is null"); + + if (!channel.permissionsFor(message.guild.roles.everyone).has(permissionBitField.SendMessages)) return "Channel is already locked"; - channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: false }); + channel.permissionOverwrites.edit(message.guild.roles.everyone, { SEND_MESSAGES: false }); const embed = new EmbedBuilder() .setTitle("Channel Updates") .setDescription(`<#${channel.id}> in now locked!`) .setColor(Colors.Red) - // @ts-expect-error + // @ts-expect-error // FIXME: Fix this .setFooter(client.config.embedFooter(client)) - .setTimestamp(new Date()) + .setTimestamp(new Date()); return { embeds: [embed] }; } diff --git a/commands/moderation/nickname.ts b/commands/moderation/nickname.ts index 8edb5a0..1cd06c1 100644 --- a/commands/moderation/nickname.ts +++ b/commands/moderation/nickname.ts @@ -22,19 +22,23 @@ module.exports = { } ], + commandOptions: { + guildOnly: true, + }, + default_member_permissions: permissionStrings.ManageNicknames, async run(_client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error - let mentionedMember = message.mentions.members.first() || message.guild!.members.cache.get(args[0]); + // @ts-expect-error // TODO: fix line above + let mentionedMember = message.mentions.members.first() || message.guild?.members.cache.get(args[0]); let nickName; - if (mentionedMember === void 0) { + if (mentionedMember === undefined) { nickName = args.slice(0).join(" "); mentionedMember = message.member; } else nickName = args.slice(1).join(" "); - if (nickName === void 0) return "Please provide a nickname for me to change this users nickname"; + if (nickName === undefined) return "Please provide a nickname for me to change this users nickname"; try { const username = mentionedMember.nickname || mentionedMember.user.username; diff --git a/commands/moderation/prepare.ts b/commands/moderation/prepare.ts index 92699f7..b2624e0 100644 --- a/commands/moderation/prepare.ts +++ b/commands/moderation/prepare.ts @@ -1,22 +1,18 @@ import { Command } from "../../types/command"; import Client from "../../types/client"; import { CommandInteraction, Message } from "discord.js"; +import permissionStrings from "../../enums/permissionStrings"; const { EmbedBuilder } = require("discord.js"); const registering = (client: Client, message: CommandInteraction | Message) => { - // @ts-expect-error - if (!message.member!.permissions.has("ADMINISTRATOR")) return new EmbedBuilder() - .setTitle("Failed to create slash-commands") - .setDescription("You do not have permissions to create slash-commands"); - const embed = new EmbedBuilder() - .setTitle("Success") + .setTitle("Success"); client.commands.forEach((command: Command) => { if (command.name === "prepare") return; // @ts-expect-error // cause name can't be undefined, look at index.ts - message.guild!.commands?.create(command).catch((error: Error) => { + message.guild?.commands?.create(command).catch((error: Error) => { return new EmbedBuilder() .setTitle("Failed to create slash-commands") .setDescription(error.toString()); @@ -24,11 +20,13 @@ const registering = (client: Client, message: CommandInteraction | Message }); return embed; -} +}; module.exports = { description: "Creates slash commands in server", + default_member_permissions: permissionStrings.Administrator, + async run(client, message, _args, _guildData, _userData, _isSlashCommand) { const embed = registering(client, message); return { embeds: [embed] }; diff --git a/commands/moderation/set-counter-channel.ts b/commands/moderation/set-counter-channel.ts index c133fa3..53d41f2 100644 --- a/commands/moderation/set-counter-channel.ts +++ b/commands/moderation/set-counter-channel.ts @@ -3,6 +3,7 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; +import { GuildData } from "../../types/data"; module.exports = { ignore: true, //TODO: Needs fix ASAP @@ -21,13 +22,12 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === void 0) channel = message.channel; + if (channel === undefined) channel = message.channel; const current = guildData.channels; current.counter = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: GuildData) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/moderation/set-goodbye-channel.ts b/commands/moderation/set-goodbye-channel.ts index 2eb0d43..525c29a 100644 --- a/commands/moderation/set-goodbye-channel.ts +++ b/commands/moderation/set-goodbye-channel.ts @@ -3,6 +3,7 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; +import { GuildData } from "../../types/data"; module.exports = { ignore: true, //TODO: Needs fix ASAP @@ -21,13 +22,12 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; const current = guildData.channels; current.goodbye = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: GuildData) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/moderation/set-welcome-channel.ts b/commands/moderation/set-welcome-channel.ts index 51a2936..557354e 100644 --- a/commands/moderation/set-welcome-channel.ts +++ b/commands/moderation/set-welcome-channel.ts @@ -3,6 +3,7 @@ import { ApplicationCommandOptionType } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; import guilds from "../../schemas/guild"; +import { GuildData } from "../../types/data"; module.exports = { ignore: true, //TODO: Needs fix ASAP @@ -21,13 +22,12 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, async run(_client, message, args, guildData, _userData, _isSlashCommand) { - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; const current = guildData.channels; current.welcome = channel.id; - guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: any) => { + guilds.findByIdAndUpdate(guildData._id, { channels: current }, (err: Error, data: GuildData) => { if (err) console.error(err); if (!data) return "Error: User not found."; }); diff --git a/commands/moderation/slowmode.ts b/commands/moderation/slowmode.ts index 7eff7cc..498271d 100644 --- a/commands/moderation/slowmode.ts +++ b/commands/moderation/slowmode.ts @@ -26,9 +26,8 @@ module.exports = { run(_client, message, args, _guildData, _userData, _isSlashCommand) { let rate; - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); - if (channel === void 0) { + if (channel === undefined) { channel = message.channel; rate = args[0]; } else rate = args[1]; diff --git a/commands/moderation/tempban.ts b/commands/moderation/tempban.ts index 9f39f40..8af34fc 100644 --- a/commands/moderation/tempban.ts +++ b/commands/moderation/tempban.ts @@ -26,7 +26,7 @@ module.exports = { default_member_permissions: permissionStrings.BanMembers, - run(client, message, args, guildData, userData, isSlashCommand) { + run(_client, _message, _args, _guildData, _userData, _isSlashCommand) { } diff --git a/commands/moderation/unban.ts b/commands/moderation/unban.ts index 1a8b692..9fcd411 100644 --- a/commands/moderation/unban.ts +++ b/commands/moderation/unban.ts @@ -16,20 +16,25 @@ module.exports = { } ], + commandOptions: { + guildOnly: true + }, + + default_member_permissions: permissionStrings.BanMembers, async run(_client, message, args, _guildData, _userData, _isSlashCommand) { - if (args[0] === void 0) + if (args[0] === undefined) return "Please Give Me Member ID That You Want To Unban!"; - const bans = await message.guild!.bans.fetch(); - const member = bans.find(b => b.user.username.toLowerCase() === args[0].toLocaleLowerCase()) || bans.get(args[0]) || bans.find(bm => bm.user.tag.toLowerCase() === args[0].toLocaleLowerCase()); + const bans = await message.guild?.bans.fetch(); + const member = bans?.find(b => b.user.username.toLowerCase() === args[0].toLocaleLowerCase()) || bans?.get(args[0]) || bans?.find(bm => bm.user.tag.toLowerCase() === args[0].toLocaleLowerCase()); - if (member === void 0) + if (member === undefined) return "Please Give Valid Member ID Or Member Is Not Banned!"; try { - await message.guild!.members.unban(member.user.id, args[1] || "No Reason Provided!"); + await message.guild?.members.unban(member.user.id, args[1] || "No Reason Provided!"); return `Unbanned <@!${args[0]}>. With reason: ${args[1] || "No Reason Provided!"}`; } catch (error) { return "I Can't Unban That Member Maybe Member Is Not Banned Or Some Error!"; diff --git a/commands/moderation/unlock.ts b/commands/moderation/unlock.ts index c09c48e..361153b 100644 --- a/commands/moderation/unlock.ts +++ b/commands/moderation/unlock.ts @@ -21,22 +21,21 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, run(client, message, args, _guildData, _userData, _isSlashCommand) { - // @ts-expect-error let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; - if (channel.permissionsFor(message.guild!.roles.everyone).has(permissionBitField.SendMessages)) + if (channel.permissionsFor(message.guild?.roles.everyone).has(permissionBitField.SendMessages)) return "Channel isn't locked"; - channel.permissionOverwrites.edit(message.guild!.roles.everyone, { SEND_MESSAGES: true }); + channel.permissionOverwrites.edit(message.guild?.roles.everyone, { SEND_MESSAGES: true }); const embed = new EmbedBuilder() .setTitle("Channel Updates") .setDescription(`<#${channel.id}> is now unlocked!`) .setColor(Colors.Red) - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)) - .setTimestamp(new Date()) + .setTimestamp(new Date()); return { embeds: [embed] }; } diff --git a/commands/music/nowPlaying.ts b/commands/music/nowPlaying.ts index 1b5aa76..423f173 100644 --- a/commands/music/nowPlaying.ts +++ b/commands/music/nowPlaying.ts @@ -8,13 +8,13 @@ module.exports = { }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - if (client.player.getQueue(message.guild!.id) === void 0) { + if (client.player.getQueue(message.guild?.id) === undefined) { return "There is no queue"; } - const current = client.player.getCurrent(message.guild!.id); + const current = client.player.getCurrent(message.guild?.id); - if (current === void 0) { + if (current === undefined) { return "Currently not playing anything"; } diff --git a/commands/music/play.ts b/commands/music/play.ts index 88fc3c2..708017c 100644 --- a/commands/music/play.ts +++ b/commands/music/play.ts @@ -18,6 +18,9 @@ module.exports = { async run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // cause it's getting caught anyway try { message.suppressEmbeds(true); } catch (e) { } - return client.player.addTrack(message, args); + const startMillis = Date.now(); + const returnVar = await client.player.addTrack(message, args); + console.debug(`Command ${this.name} took ${Date.now() - startMillis}ms to execute`); + return returnVar; } } as Command; diff --git a/commands/music/queue.ts b/commands/music/queue.ts index d3e7bfb..b23f96f 100644 --- a/commands/music/queue.ts +++ b/commands/music/queue.ts @@ -8,13 +8,13 @@ module.exports = { }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { - const playerInfo = client.player.getQueue(message.guild!.id); + const playerInfo = client.player.getQueue(message.guild?.id); - if (playerInfo === void 0) { + if (playerInfo === undefined) { return "There are no songs in the queue"; } - let currentString = `Current: **${playerInfo.current.title}**\n`; + const currentString = `Current: **${playerInfo.current.title}**\n`; let queueString = ""; for (let i = 0; i < Math.min(playerInfo.queue.length, 18); i++) { diff --git a/commands/music/troll.ts b/commands/music/troll.ts index c0864d8..c3c855b 100644 --- a/commands/music/troll.ts +++ b/commands/music/troll.ts @@ -1,3 +1,4 @@ +import { CommandInteraction } from "discord.js"; import { Command } from "../../types/command"; module.exports = { @@ -7,9 +8,8 @@ module.exports = { description: "A wild troll appeared.", connectedToVC: true, - run(client, message, _args, _guildData, _userData, isSlashCommand) { - // @ts-expect-error - if (!isSlashCommand) message.delete(); + run(client, message, _args, _guildData, _userData, _isSlashCommand) { + if (!(message instanceof CommandInteraction)) message.delete(); // @ts-expect-error // Log the user using the command cause roteKlaue console.log(`${message.author.username} used the troll command.`); diff --git a/commands/testcommands/ping.ts b/commands/testcommands/ping.ts index cc35fd7..fd0c50c 100644 --- a/commands/testcommands/ping.ts +++ b/commands/testcommands/ping.ts @@ -20,7 +20,7 @@ const after = (client: Client, message: Message, sentMessage: Message, sta sentMessage.delete(); return { embeds: [embed] }; } -} +}; //TODO: I implemented returning null for a reason... So ig I should use it here @@ -39,9 +39,9 @@ module.exports = { after(client, message, msg, StartDate, true); }); } else { - return message.channel!.send(sendObj) + return message.channel?.send(sendObj) // @ts-expect-error // FIXME pls, this is pure agony - .then((msg) => { return after(client, message, msg, StartDate) }); + .then((msg) => { return after(client, message, msg, StartDate); }); } } } as Command; diff --git a/commands/testcommands/playtest.ts b/commands/testcommands/playtest.ts index 707b5a8..be58f1c 100644 --- a/commands/testcommands/playtest.ts +++ b/commands/testcommands/playtest.ts @@ -62,4 +62,4 @@ const songList = [ "https://www.youtube.com/watch?v=7T2sjD4bJU8&list=RDMM&index=49", "https://www.youtube.com/watch?v=yebo5ILBMC0&list=RDMM&index=50", "https://www.youtube.com/watch?v=-N4jf6rtyuw&list=RDMM&index=51" -] +]; diff --git a/enums/permissionBitField.ts b/enums/permissionBitField.ts index bd472aa..243b17c 100644 --- a/enums/permissionBitField.ts +++ b/enums/permissionBitField.ts @@ -40,4 +40,4 @@ export default { SendMessagesInThreads: 1n << 38n, UseEmbeddedActivities: 1n << 39n, ModerateMembers: 1n << 40n, -} \ No newline at end of file +}; diff --git a/enums/permissionStrings.ts b/enums/permissionStrings.ts index 3888ca7..c2c18b6 100644 --- a/enums/permissionStrings.ts +++ b/enums/permissionStrings.ts @@ -40,4 +40,4 @@ export default { SendMessagesInThreads: "0x0000004000000000", UseEmbeddedActivities: "0x0000008000000000", ModerateMembers: "0x0000010000000000" -} +}; diff --git a/events/discord/guildCreate.ts b/events/discord/guildCreate.ts index a747c96..ea2729d 100644 --- a/events/discord/guildCreate.ts +++ b/events/discord/guildCreate.ts @@ -1,4 +1,3 @@ -// @ts-ignore import guildModel from "../../schemas/guild"; import { Guild, ApplicationCommandDataResolvable } from "discord.js"; @@ -10,11 +9,10 @@ module.exports = async (client: Client, guild: Guild) => { console.info("Creating MongoDB entry for guild " + guild.name); - // @ts-ignore global.functions.addGuildDocument(guild.id); client.commands.forEach(command => { if (command.name === "prepare") return; guild.commands?.create(command as ApplicationCommandDataResolvable).catch(e => e); }); -} +}; diff --git a/events/discord/guildDelete.ts b/events/discord/guildDelete.ts index 7bcbe2c..a8fac01 100644 --- a/events/discord/guildDelete.ts +++ b/events/discord/guildDelete.ts @@ -1,9 +1,9 @@ import guildModel from "../../schemas/guild"; -import { Guild, ApplicationCommandDataResolvable } from "discord.js"; +import { Guild } from "discord.js"; import Client from "../../types/client"; module.exports = async (client: Client, guild: Guild) => { console.info("Deleting MongoDB entry for guild " + guild.name); guildModel.findOneAndDelete({ guildId: guild.id }, () => { }); -} +}; diff --git a/events/discord/guildMemberAdd.ts b/events/discord/guildMemberAdd.ts index 9b5931e..e28893a 100644 --- a/events/discord/guildMemberAdd.ts +++ b/events/discord/guildMemberAdd.ts @@ -7,8 +7,8 @@ import guilds from "../../schemas/guild"; module.exports = async (client: Client, member: GuildMember) => { const guild = await guilds.findOne({ guildId: member.guild.id }); - if (guild?.channels?.welcome === void 0) return; + if (guild?.channels?.welcome === undefined) return; const channel = client.channels.cache.get(guild.channels.welcome); // @ts-expect-error // i gotta stop doing this channel.send(global.functions.replaceUser(welcomeMessages[Math.floor(Math.random() * welcomeMessages.length)], member)); -} +}; diff --git a/events/discord/guildMemberRemove.ts b/events/discord/guildMemberRemove.ts index f695775..46f8187 100644 --- a/events/discord/guildMemberRemove.ts +++ b/events/discord/guildMemberRemove.ts @@ -11,4 +11,4 @@ module.exports = async (client: Client, member: GuildMember) => { const channel = client.channels.cache.get(guild?.channels?.goodbye); // @ts-expect-error // I hate this // FIXME: PLS!!! // i gotta stop doing this channel.send(global.functions.replaceUser(goodbyeMessages[Math.floor(Math.random() * goodbyeMessages.length)], member)); -} +}; diff --git a/events/discord/interactionCreate.ts b/events/discord/interactionCreate.ts index 9276185..fa179cd 100644 --- a/events/discord/interactionCreate.ts +++ b/events/discord/interactionCreate.ts @@ -55,11 +55,10 @@ module.exports = async (client: Client, interaction: Interaction) => { return; } - const modifiedInteraction = interaction as any; + const modifiedInteraction = interaction as unknown; // console.log(typeof modifiedInteraction) // modifiedInteraction.channel = client.channels.cache.get(modifiedInteraction.channelId); // modifiedInteraction.author = modifiedInteraction.user; - // @ts-expect-error // i gotta stop doing this global.functions.executeCommand(cmd, client, modifiedInteraction, args, true, isComponent); -} +}; diff --git a/events/discord/messageCreate.ts b/events/discord/messageCreate.ts index 5715b7a..b83098d 100644 --- a/events/discord/messageCreate.ts +++ b/events/discord/messageCreate.ts @@ -5,12 +5,11 @@ import guildModel from "../../schemas/guild"; module.exports = async (client: Client, message: Message) => { if (message.author.bot) return; // Ignore bots + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const guildData = await getGuildData(message.guild!.id); - // @ts-expect-error // i gotta stop doing this if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function - // @ts-expect-error // same as above if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels const prefix = client.config.prefix; // Get the prefix from the .env file @@ -18,20 +17,19 @@ module.exports = async (client: Client, message: Message) => { if (!message.content.startsWith(prefix)) return; // Ignore messages that don't start with the prefix const args = message.content.slice(prefix.length).trim().split(/ +/g); // Get the arguments + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const commandString = args.shift()!.toLowerCase(); // Get the command name const command = client.commands.get("command:" + commandString) || // Get the command from the commands collection client.commands.find(command => command.aliases && command.aliases.includes(commandString)); // @ts-expect-error // I am God, I can create whatever I want TS! message.followUp = message.reply; - // @ts-expect-error // i gotta stop doing this global.functions.executeCommand(command, client, message, args, false); // Execute the command -} +}; async function getGuildData(guildId: string) { let guildData = await guildModel.findOne({ guildId: guildId }); if (!guildData) { - // @ts-expect-error // i gotta stop doing this global.functions.addGuildDocument(guildId); guildData = await guildModel.findOne({ guildId: guildId }); } diff --git a/events/discord/ready.ts b/events/discord/ready.ts index 7d91766..7954996 100644 --- a/events/discord/ready.ts +++ b/events/discord/ready.ts @@ -4,4 +4,4 @@ module.exports = (client: Client) => { client.user.setActivity(`${client.config.prefix}help`); // @ts-expect-error // it really does... console.success("Bot is ready!"); -} +}; diff --git a/events/mongodb/connected.ts b/events/mongodb/connected.ts index b4bafee..4cda6c8 100644 --- a/events/mongodb/connected.ts +++ b/events/mongodb/connected.ts @@ -1,6 +1,6 @@ import { Connection } from "mongoose"; -module.exports = (client: Connection) => { +module.exports = (_client: Connection) => { // @ts-expect-error // gotta add success to the console type console.success("MongoDB connection is ready!"); } diff --git a/events/mongodb/connecting.ts b/events/mongodb/connecting.ts index b16f1e6..bd105fe 100644 --- a/events/mongodb/connecting.ts +++ b/events/mongodb/connecting.ts @@ -1,5 +1,5 @@ import { Connection } from "mongoose"; -module.exports = (client: Connection) => { +module.exports = (_client: Connection) => { console.info("Connecting to MongoDB..."); -} +}; diff --git a/events/mongodb/disconnected.ts b/events/mongodb/disconnected.ts index a67d01d..92aa88f 100644 --- a/events/mongodb/disconnected.ts +++ b/events/mongodb/disconnected.ts @@ -1,5 +1,5 @@ import { Connection } from "mongoose"; -module.exports = (client: Connection) => { +module.exports = (_client: Connection) => { console.warn("MongoDB connection destroyed!"); -} +}; diff --git a/events/mongodb/err.ts b/events/mongodb/err.ts index 779ac36..63dc3f9 100644 --- a/events/mongodb/err.ts +++ b/events/mongodb/err.ts @@ -2,4 +2,4 @@ import { Connection } from "mongoose"; module.exports = (client: Connection, err: Error) => { console.error(err); -} +}; diff --git a/functions/addGuildDocument.ts b/functions/addGuildDocument.ts index 463af8a..f822868 100644 --- a/functions/addGuildDocument.ts +++ b/functions/addGuildDocument.ts @@ -2,6 +2,7 @@ import guildModel from "../schemas/guild"; import { Types } from "mongoose"; export default (guildId: string) => { + if (!guildId) throw new Error("No guildId provided."); (new guildModel({ _id: new Types.ObjectId(), guildId: guildId, @@ -21,4 +22,4 @@ export default (guildId: string) => { warns: [], tempBans: [], })).save(); -} +}; diff --git a/functions/addUserDocument.ts b/functions/addUserDocument.ts index 5c2f4b6cd..a3de9e9 100644 --- a/functions/addUserDocument.ts +++ b/functions/addUserDocument.ts @@ -6,4 +6,4 @@ export default (userId: string) => { _id: Types.ObjectId(), userId: userId, })).save(); -} +}; diff --git a/functions/checkChannelID.ts b/functions/checkChannelID.ts index 006602e..9d3fdc1 100644 --- a/functions/checkChannelID.ts +++ b/functions/checkChannelID.ts @@ -1,9 +1,8 @@ -import { Guild, Message } from "discord.js"; +import { Message } from "discord.js"; +import { GuildData } from "../types/data"; -const fetchData = require("./fetchDataFromSave"); - -module.exports = (message: Message, guildData: any) => { - if (guildData?.channels?.allowed === void 0) return true; +module.exports = (message: Message, guildData: GuildData) => { + if (guildData?.channels?.allowed === undefined) return true; const allowedChannelsIDS = guildData.channels.allowed; if (Array.isArray(allowedChannelsIDS)) { if (allowedChannelsIDS.length === 0) return true; @@ -11,4 +10,4 @@ module.exports = (message: Message, guildData: any) => { } else { return allowedChannelsIDS === message.channel.id; } -} +}; diff --git a/functions/convertTime.ts b/functions/convertTime.ts index e891b80..7580c86 100644 --- a/functions/convertTime.ts +++ b/functions/convertTime.ts @@ -13,10 +13,15 @@ module.exports = (seconds: number) => { return returnString; else return "0s"; -} +}; -function secondsConverter(seconds: number) { - const timeObj: any = {}; +function secondsConverter(seconds: number): TimeObj { + const timeObj: TimeObj = { + days: 0, + hours: 0, + minutes: 0, + seconds: 0 + }; timeObj.days = Math.floor(seconds / 86400); seconds -= timeObj.days * 86400; timeObj.hours = Math.floor(seconds / 3600); @@ -25,4 +30,11 @@ function secondsConverter(seconds: number) { seconds -= timeObj.minutes * 60; timeObj.seconds = Math.floor(seconds); return timeObj; +} + +interface TimeObj { + days: number; + hours: number; + minutes: number; + seconds: number; } \ No newline at end of file diff --git a/functions/counter.ts b/functions/counter.ts index 83c22f5..2267870 100644 --- a/functions/counter.ts +++ b/functions/counter.ts @@ -1,18 +1,18 @@ import { Message } from "discord.js"; import guilds from "../schemas/guild"; +import { GuildData } from "../types/data"; -module.exports = (message: Message, guildData: any) => { - ; - if (guildData?.channels?.counter === void 0) return; +module.exports = (message: Message, guildData: GuildData) => { + if (guildData?.channels?.counter === undefined) return; if (!(guildData.channels.counter === message.channel.id)) return false; const current = guildData.counter.current; if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) - guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: any) => { + guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: GuildData) => { if (err) console.error(err); (err); - if (!data) return "No data found" + if (!data) return "No data found"; }); else message.delete().catch(); return true; -} +}; diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index a590b8e..ce20fad 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -1,39 +1,43 @@ -import { PermissionResolvable, Message } from "discord.js"; -import { Command, CommandReturnWithoutString } from "../types/command"; +import { PermissionResolvable, Message, ActionRowBuilder } from "discord.js"; +import { Command, CommandReturns, CommandReturnWithoutString } from "../types/command"; import Client from "../types/client"; +import logTime from "../logTime"; // TODO: Add automated argument checking import getGuildData from "./getGuildData"; import getUserData from "./getUserData"; -// @ts-expect-error -import formatCommandReturn from "./formatCommandReturn"; import sendMessage from "./sendMessage"; module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { - if (command === void 0) return; + if (command === undefined) return; + if (interaction === undefined) return; + if (interaction.member === null) return interaction.reply("You need to be in a server to use this command."); + if (client === undefined) return interaction.reply("The bot is currently restarting. Please try again in a few seconds."); - // @ts-expect-error + // @ts-expect-error // It will only use the .message property if it's a component interaction interaction.author ||= interaction.message.author; + if (command.ignore) return interaction.reply("This command is currently disabled."); + if (command.default_member_permissions && !isInteraction - && !interaction!.member!.permissions.has(command!.default_member_permissions as PermissionResolvable)) { + && !interaction.member.permissions.has(command.default_member_permissions as PermissionResolvable)) { const permissionString = getPermissionsString(command.default_member_permissions); const moreThanOne = (permissionString.match(/,/g) || []).length; const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; return interaction.reply(outputString); } - if (command!.commandOptions?.connectedToSameVC) - command!.commandOptions.connectedToVC = true; + if (command.commandOptions?.connectedToSameVC) + command.commandOptions.connectedToVC = true; - if (command!.commandOptions?.connectedToVC && !interaction!.member!.voice?.channel) + if (command.commandOptions?.connectedToVC && !interaction.member.voice?.channel) return interaction.reply("You need to be in a voice channel to use this command."); - if (command!.commandOptions?.connectedToSameVC && client!.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction!.member!.voice?.channel?.id) { - if (client.player.getQueue(interaction.guildId)?.voiceChannel === void 0) + if (command.commandOptions?.connectedToSameVC && client.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction.member.voice?.channel?.id) { + if (client.player.getQueue(interaction.guildId)?.voiceChannel === undefined) return interaction.reply("I am not in a voice channel."); return interaction.reply("You need to be in the same voice channel as me to use this command."); } @@ -43,22 +47,24 @@ module.exports = async (command: Command, client: Client, interaction: Mes // makes reply unavailable so two replies can't be sent const reply = interaction.reply; - interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand. Use return or message.channel.send() instead!") }; + interaction.reply = () => { throw new Error("Cannot reply outside of executeCommand. Use return or message.channel.send() instead!"); }; // @ts-expect-error const deferReply = interaction.deferReply; // @ts-expect-error - interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand. Use return null instead!") }; + interaction.deferReply = () => { throw new Error("Cannot defer reply outside of executeCommand. Use return null instead!"); }; try { - if (command!.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); + if (command.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); let guildData; if (interaction.guild) guildData = await getGuildData(interaction.guild.id); - let userData = await getUserData(interaction.author.id); + const userData = await getUserData(interaction.author.id); - let returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); + const startTime = process.hrtime(); + const returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); + logTime(command, process.hrtime(startTime)); if (returnValue === null) { // @ts-expect-error @@ -69,19 +75,19 @@ module.exports = async (command: Command, client: Client, interaction: Mes } // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - let success = returnValue.success || command!.commandOptions?.defaultReturn?.success; + const success = returnValue.success || command.commandOptions?.defaultReturn?.success; if (success) { - if (returnValue!.setCooldown) + if (returnValue.setCooldown) returnValue.setCooldown.push(command); else - returnValue!.setCooldown = [command]; + returnValue.setCooldown = [command]; } // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - let cooldownArray: Command[] | undefined = returnValue!.setCooldown || command!.commandOptions?.defaultReturn?.setCooldown; + const cooldownArray: Command[] | undefined = returnValue.setCooldown || command.commandOptions?.defaultReturn?.setCooldown; - if (cooldownArray !== void 0) + if (cooldownArray !== undefined) cooldownArray.forEach(commandObject => { setCooldown(commandObject, interaction, client); }); @@ -89,7 +95,7 @@ module.exports = async (command: Command, client: Client, interaction: Mes // makes reply available again interaction.reply = reply; - if (returnValue.DM !== void 0 && returnValue.DM !== null) { + if (returnValue.DM !== undefined && returnValue.DM !== null) { sendMessage(returnValue.DM, command, client, interaction, args, isInteraction, guildData, userData, true); } @@ -97,14 +103,13 @@ module.exports = async (command: Command, client: Client, interaction: Mes sendMessage(returnValue, command, client, interaction, args, isInteraction, guildData, userData, false); // @ts-expect-error // cause if it's undefined, it's not doing anything anyway - const disable = returnValue.disableOriginal || command!.commandOptions?.defaultReturn?.disableOriginal; + const disable = returnValue.disableOriginal || command.commandOptions?.defaultReturn?.disableOriginal; if (disable && isComponent) { - // @ts-expect-error + // @ts-expect-error // I gotta fix the line above first cause I need to check if it's a component interaction in a type-safe way const originalMessage = await interaction.message; - // @ts-expect-error - originalMessage.components.forEach(actionRow => { - // @ts-expect-error + originalMessage.components.forEach((actionRow: ActionRowBuilder) => { actionRow.components.forEach(component => { + // @ts-expect-error // If it doesn't exist and I add it anyway, it won't do any harm component.data.disabled = true; }); }); @@ -115,12 +120,12 @@ module.exports = async (command: Command, client: Client, interaction: Mes } catch (e) { // makes reply available again interaction.reply = reply; - // @ts-expect-error + // @ts-expect-error // If it doesn't exist and I add it anyway, it won't do any harm if (isInteraction) interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(() => { }); else interaction.reply("An error occurred while executing this command.").catch(() => { }); console.error(e); } -} +}; // function that converts default_member_permissions bitfield to a human readable string @@ -168,35 +173,72 @@ function setCooldown(commandString: Command | string, interaction: Message, clie let command: Command; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); - if (getCommand === void 0) return console.error("Could not set cooldown, command not found: " + commandString); + if (getCommand === undefined) return console.error("Could not set cooldown, command not found: " + commandString); command = getCommand; } else command = commandString; - if (typeof command!.commandOptions?.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + command.name); - if (command.name === void 0) return console.error("Could not set cooldown, command has no name: " + command.name); - client.commandCooldowns.get(command.name)!.set(interaction!.author.id, Date.now() + command!.commandOptions?.cooldown * 1000); + if (typeof command.commandOptions?.cooldown !== "number") return console.error("Could not set cooldown, command has no cooldown: " + command.name); + if (command.name === undefined) return console.error("Could not set cooldown, command has no name: " + command.name); + const cooldown = client.commandCooldowns.get(command.name); + if (cooldown === undefined) throw new Error("Could not set cooldown, command not found: " + command.name); + cooldown.set(interaction.author.id, Date.now() + command.commandOptions?.cooldown * 1000); setTimeout(() => { - client.commandCooldowns.get(command.name as string)!.delete(interaction!.author.id); - }, command!.commandOptions?.cooldown * 1000); + cooldown.delete(interaction.author.id); + }, command.commandOptions?.cooldown * 1000); } function checkCooldown(commandString: Command | string, interaction: Message, client: Client): string | boolean { let command: Command; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); - if (getCommand === void 0) throw new Error("Could not check cooldown, command not found: " + commandString); + if (getCommand === undefined) throw new Error("Could not check cooldown, command not found: " + commandString); command = getCommand; } else command = commandString; - if (command.name === void 0) throw new Error("Could not check cooldown, command has no name: " + command.name); - if (client.commandCooldowns.get(command.name)!.has(interaction!.author.id)) { - let timeLeft = client.commandCooldowns.get(command.name)!.get(interaction!.author.id)! - Date.now(); - timeLeft /= 1000; - if (timeLeft > 0) { - // @ts-expect-error - const timeString = global.functions.convertTime(timeLeft); - return `You are on cooldown for this command, please wait ${timeString}.` - } + if (command.name === undefined) throw new Error("Could not check cooldown, command has no name: " + command.name); + const cooldown = client.commandCooldowns.get(command.name); + if (cooldown === undefined) throw new Error("Could not set cooldown, command not found: " + command.name); + const authorCooldown = cooldown.get(interaction.author.id); + if (authorCooldown === undefined) return false; + let timeLeft = authorCooldown - Date.now(); + timeLeft /= 1000; + if (timeLeft < 0) { + cooldown.delete(interaction.author.id); + return false; } - return false; + const timeString = global.functions.convertTime(timeLeft); + return `You are on cooldown for this command, please wait ${timeString}.`; +} + +async function formatCommandReturn(returnValue: CommandReturns, command: Command): Promise { + // eslint-disable-next-line no-async-promise-executor + return await new Promise(async (resolve, reject) => { + if (returnValue instanceof Promise) { + const timeout = setTimeout(() => { + reject(`Command ${command.name} took too long to execute!`); + }, 4500); + returnValue = await returnValue; + clearTimeout(timeout); + } + if (typeof returnValue === "string") returnValue = { content: returnValue } as CommandReturnWithoutString; + returnValue = returnValue as CommandReturnWithoutString; + if (!checkIfValid(returnValue)) reject(`Command "${command.name}" returned nothing.`); + // @ts-expect-error // FIXME: I don't have the mental capacity to fix this rn + if (returnValue?.DM !== undefined) returnValue.DM = await formatCommandReturn(returnValue.DM, command); + resolve(returnValue); + }); +} + +function checkIfValid(returnValue: CommandReturnWithoutString) { + return ( + (returnValue?.embeds !== undefined + || returnValue?.files !== undefined + || returnValue?.components !== undefined + || returnValue?.content !== undefined + || returnValue?.files !== undefined + // @ts-expect-error // I'm checking if it exists, so it's fine ig + || returnValue?.attachments !== undefined + && !(returnValue instanceof Message)) + || returnValue === null + ); } \ No newline at end of file diff --git a/functions/fetchDataFromSave.ts b/functions/fetchDataFromSave.ts index 515b455..2a23cbb 100644 --- a/functions/fetchDataFromSave.ts +++ b/functions/fetchDataFromSave.ts @@ -8,7 +8,7 @@ module.exports = { get: (key: string) => { return data[key]; }, - set: (key: string, value: any) => { + set: (key: string, value: unknown) => { data[key] = value; }, write: () => { @@ -16,4 +16,4 @@ module.exports = { wStream.write(JSON.stringify(data)); wStream.end(); } -} +}; diff --git a/functions/formatCommandReturn.ts b/functions/formatCommandReturn.ts deleted file mode 100644 index 566e512..0000000 --- a/functions/formatCommandReturn.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Command, CommandReturns } from "../types/command"; - -const { Message } = require("discord.js"); - -module.exports = async (returnValue: any, command: Command) => { - return await new Promise(async (resolve, reject) => { - if (returnValue instanceof Promise) { - const timeout = setTimeout(() => { - reject(`Command ${command.name} took too long to execute!`); - }, 4500); - returnValue = await returnValue; - clearTimeout(timeout); - } - if (( - (typeof returnValue === "string" && returnValue !== "") - || returnValue?.embeds !== void 0 - || returnValue?.files !== void 0 - || returnValue?.components !== void 0 - || returnValue?.content !== void 0 - || returnValue?.files !== void 0 - || returnValue?.attachments !== void 0 - ) && !(returnValue instanceof Message)) { - if (typeof returnValue === "string") returnValue = { content: returnValue }; - } else if (returnValue?.DM !== void 0) { - returnValue.DM = module.exports(returnValue.DM, command); - } else if (returnValue !== null) reject(`Command "${command.name}" returned nothing.`); - resolve(returnValue); - }); -} \ No newline at end of file diff --git a/functions/getChannelFromMention.ts b/functions/getChannelFromMention.ts index 438d2c3..99e0c59 100644 --- a/functions/getChannelFromMention.ts +++ b/functions/getChannelFromMention.ts @@ -3,4 +3,4 @@ import { Guild } from "discord.js"; module.exports = (guild: Guild, mention: string) => { if (!mention) return; return guild.channels.cache.get(mention.substring(2, mention.length - 1)); -} +}; diff --git a/functions/getFiles.ts b/functions/getFiles.ts index 56f2db4..084cd0a 100644 --- a/functions/getFiles.ts +++ b/functions/getFiles.ts @@ -1,17 +1,27 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ const fs = require("fs"); -const getFiles = (dir: string, exclude = null) => { +const getFiles = (dir: string, exclude?: string): any => { const output: any = {}; fs.readdirSync(dir).forEach((path: string) => { if (fs.lstatSync(dir + "/" + path).isDirectory()) { output[path] = getFiles(dir + "/" + path, exclude); } else { if (!path.endsWith(".js") && !path.endsWith(".ts")) return; - const func = require(`.${dir}/${path}`); + let func = require(`.${dir}/${path}`); + // count number of functions in func + let count = 0; + for (const key in func) { + if (Object.prototype.hasOwnProperty.call(func, key)) { + count++; + } + } + // if ONLY default export exists, set func to that + if (func.default && count === 1) func = func.default; output[path.replace(".js", "").replace(".ts", "")] = func; } }); return output; -} +}; -module.exports = getFiles; +export default getFiles; diff --git a/functions/getGuildData.ts b/functions/getGuildData.ts index b576654..b83deb8 100644 --- a/functions/getGuildData.ts +++ b/functions/getGuildData.ts @@ -1,11 +1,12 @@ import guildModel from "../schemas/guild"; import addGuildDocument from "./addGuildDocument"; +import { GuildData } from "../types/data"; -export default async (guildId: string) => { +export default async (guildId: string): Promise => { let guildData = await guildModel.findOne({ guildId: guildId }); if (!guildData) { addGuildDocument(guildId); guildData = await guildModel.findOne({ guildId: guildId }); } return guildData; -} +}; diff --git a/functions/getUserData.ts b/functions/getUserData.ts index 1fa32bc..a498481 100644 --- a/functions/getUserData.ts +++ b/functions/getUserData.ts @@ -1,11 +1,12 @@ import userModel from "../schemas/user"; import addUserDocument from "./addUserDocument"; +import { UserData } from "../types/data"; -export default async (userId: string) => { +export default async (userId: string): Promise => { let userData = await userModel.findOne({ userId: userId }); if (!userData) { addUserDocument(userId); userData = await userModel.findOne({ userId: userId }); } return userData; -} +}; diff --git a/functions/replaceUser.ts b/functions/replaceUser.ts index 564bab1..31ff0dc 100644 --- a/functions/replaceUser.ts +++ b/functions/replaceUser.ts @@ -1,5 +1,5 @@ import { GuildMember } from "discord.js"; -module.exports = (message: string, member: GuildMember) => { +export default (message: string, member: GuildMember) => { return message.replace("{user}", "**" + member.user.username + "#" + member.user.discriminator + "**"); -} +}; diff --git a/functions/sendMessage.ts b/functions/sendMessage.ts index 0518c52..1767bfb 100644 --- a/functions/sendMessage.ts +++ b/functions/sendMessage.ts @@ -1,8 +1,9 @@ import { Message, Component, ButtonComponent, BaseSelectMenuComponent } from "discord.js"; import Client from "../types/client"; import { Command, CommandReturnWithoutString } from "../types/command"; +import { GuildData, UserData } from "../types/data"; -export default async (messageToSend: CommandReturnWithoutString, command: Command, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: any /*idfk*/, userData: any /*same here*/, isDM: boolean) => { +export default async (messageToSend: CommandReturnWithoutString, command: Command, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: GuildData, userData: UserData, isDM: boolean) => { let sentMessage: Message; if (messageToSend === null) return; @@ -44,7 +45,9 @@ export default async (messageToSend: CommandReturnWithoutString, command: Comman if (messageToSend.disable) { if (messageToSend.disable === true) messageToSend.disable = 5; setTimeout(() => { - messageToSend.components!.forEach((actionRow: any) => { + if (messageToSend.components === undefined) return; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Idk the type... It'll be fine, I hope + messageToSend.components.forEach((actionRow: any) => { actionRow.components.forEach((component: Component) => { if (component instanceof ButtonComponent || component instanceof BaseSelectMenuComponent) { // @ts-expect-error // I do, in fact, know what I'm doing TS... Idfc if it's read-only or not diff --git a/functions/shuffle.ts b/functions/shuffle.ts index d53f9c7..b196ed1 100644 --- a/functions/shuffle.ts +++ b/functions/shuffle.ts @@ -1,8 +1,8 @@ -module.exports = (arrayIn: any[]) => { - let array = arrayIn; +export default (arrayIn: unknown[]) => { + const array = arrayIn; for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; -} +}; diff --git a/index.ts b/index.ts index f7b95b0..c9fc6f3 100644 --- a/index.ts +++ b/index.ts @@ -3,13 +3,14 @@ //TODO: Add the ability to automatically give members with a certain level a role import { Command } from "./types/command"; import ModifiedClient from "./types/client"; +import getFiles from "./functions/getFiles"; const { Client, Collection, GatewayIntentBits } = require("discord.js"); const { connect, connection, set } = require("mongoose"); const Player = require("./music/player"); const fs = require("fs"); require("dotenv").config(); -set('strictQuery', false); +set("strictQuery", false); require("better-cl").setup(console, [], "./logs"); @@ -33,9 +34,13 @@ client.connection = connection; console.log(`Version: ${client.config.version} by ${client.config.authorsString}`); -/* Loading all the functions. */ -// @ts-expect-error -global.functions = require("./functions/getFiles")("./functions", "functions.ts"); +// att the functions object to the "global" object so that it can be accessed from anywhere and make it type safe and read-only +declare global { + // eslint-disable-next-line no-var + var functions: any; +} + +global.functions = getFiles("./functions"); /* Loading all the commands. */ [ @@ -46,6 +51,7 @@ global.functions = require("./functions/getFiles")("./functions", "functions.ts" client.commandCooldowns = new Collection(); client.commands.forEach((command: Command) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- I just set it a few lines above client.commandCooldowns.set(command.name!, new Collection()); }); @@ -76,7 +82,8 @@ client.login(process.env.TOKEN); /* Connect to the mongodb database */ connect(process.env.MONGODB); /* Starting the Webserver */ -// @ts-expect-error +console.log("Starting webserver..."); +// @ts-expect-error // TODO: I gotta find a way to add functions to the console object require("./www/index").startServer(client, process.env.PORT, () => console.success("Webserver ready!")); // makes sure the bot doesn't crash @@ -92,11 +99,10 @@ function loadCommands(dirName: string, removeTrailingS = true) { return console.warn(`./${dirName}/${dir} is not a directory.`); fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { const command = require(`./${dirName}/${dir}/${file}`); - if (command.ignore) return; command.category = `${dirNameCollection}:` + dir; command.name ||= file.replace(/(\.ts)$/, ""); command.name = `${dirNameCollection}:` + command.name.toLowerCase(); client.commands.set(command.name, command); - }) + }); }); -} \ No newline at end of file +} diff --git a/logTime.ts b/logTime.ts new file mode 100644 index 0000000..8173d79 --- /dev/null +++ b/logTime.ts @@ -0,0 +1,17 @@ +import { Command } from "./types/command"; +import fs from "fs"; + +export default (command: Command, tookTime: number[]) => { + if (!command.name) return; + const timeMs = tookTime[0] * 1000 + tookTime[1] / 1000000; + try { + fs.accessSync("./Times.json"); + } catch (err) { + fs.writeFileSync("./Times.json", "{}"); + } + const times = JSON.parse(fs.readFileSync("./Times.json", "utf-8")); + if (!times[command.name]) times[command.name] = []; + times[command.name].push(timeMs); + if (times[command.name].length > 100) times[command.name].shift(); + fs.writeFileSync("./Times.json", JSON.stringify(times, null, 4)); +}; diff --git a/music/player.js b/music/player.js deleted file mode 100644 index 83571df..0000000 --- a/music/player.js +++ /dev/null @@ -1,354 +0,0 @@ -const { createAudioPlayer, createAudioResource, joinVoiceChannel, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); -const { stream: AudioStream, video_basic_info, search, yt_validate } = require("play-dl"); -const { ImprovedArray } = require("sussy-util"); -const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } = require("discord.js"); - -const playerControls = new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setCustomId("command:queue") - .setLabel("☰") - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId("play_pause") - .setLabel("׀׀") - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId("command:stop") - .setLabel("◼") - .setStyle(ButtonStyle.Danger), - new ButtonBuilder() - .setCustomId("command:skip") - .setLabel(">>") - .setStyle(ButtonStyle.Primary), - new ButtonBuilder() - .setCustomId("support") - .setLabel("Support us!") - .setStyle(ButtonStyle.Secondary), - ); - -module.exports = class Player { - //TODO: CHANGE VARIABLE NAME FROM QUEUE TO ????? - //TODO: Add previous function --> Completely rewrite the queue system - //TODO: Add playlist support(https://stackoverflow.com/questions/13358290/how-get-all-videos-from-a-playlist-using-youtube-api) - //TODO: Add Spotify support - //TODO: Add Soundcloud support - //TODO: Don't get sued by YouTube - //TODO: Complete rewrite of the player - //BUG: See issue #17 - - #queue = new Map(); - #client; - - constructor(client) { - this.#client = client; - - this.#client.on("voiceStateUpdate", (oldState, newState) => { - const queue = this.getQueue(newState.guild.id); - - if (queue === undefined || oldState.channelId === null) { - return; - } - - if (oldState.id !== this.#client.user.id) { - if (this.#channelEmpty(oldState.channelId)) { - queue.current.channel.send("Leaving channel because it is empty."); - this.#destroyQueue(newState.guild.id); - } - return; - } - if (newState.channelId === undefined) { - queue.current.channel.send("I have been kicked from the channel."); - this.#destroyQueue(newState.guild.id); - } - - if (oldState.channelId !== newState.channelId) { - queue.voiceChannel = newState.channelId; - client.voiceChannel = newState.channelId; - } - }); - } - - #newQueue(guildId) { - this.#queue.set(guildId, { - connection: null, - voiceChannel: null, - player: null, - current: null, - loop: false, - guildId: null, - queue: new ImprovedArray() - }); - } - - #destroyQueue(guildId) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); - } - guildInfo.connection.destroy(); - this.#queue.delete(guildId); - } - - async play(guildId, track) { - const guildInfo = this.#queue.get(guildId); - if (guildInfo === undefined) return; - guildInfo.current = track; - - const stream = await AudioStream(track.url); - const resource = createAudioResource(stream.stream, { inputType: stream.type }); - - guildInfo.player.play(resource); - if (guildInfo.lastNowPlayingMessage !== undefined) { - guildInfo.lastNowPlayingMessage.delete().catch((e) => { }); - } - guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); - } - - async #createEmbed(info, type) { - const embed = new EmbedBuilder() - .setURL(info.url) - .setColor(Colors.Red) - .setTimestamp(new Date()) - .setFooter(this.#client.config.embedFooter(this.#client)); - - if (info.title) { - embed.setTitle(`${type} track ${info.title}`); - } - - if (info.thumbnails) { - const thumbnail = info.thumbnails[info.thumbnails.length - 1]; - if (thumbnail) { - embed.setImage(thumbnail.url); - } - } - - return embed; - } - - async addTrack(message, args) { - if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; - - let videoName = args.map(e => e.trim()).join(" ").trim(); - - if (videoName === "") return "Please enter the link/name of the track"; - - let url; - if (videoName.startsWith("https") && yt_validate(videoName) === "video") { - url = videoName; - } else { - const yt_infos = await search(args.join(" "), { limit: 10 }); - let currentInfo = 0; - do { - url = yt_infos[currentInfo].url; - currentInfo++; - } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); - } - - let info; - try { - info = (await video_basic_info(url)).video_details; - } catch (err) { } - if (info === undefined) { - if (this.#queue.get(message.guild.id)?.queue.length === 0) return; - let returnValue = this.skip(message); - returnValue.content = "Can't play tracks requiring age verification! Skipping..."; - return returnValue; - } - - if (!this.#queue.has(message.guild.id)) { - this.#newQueue(message.guild.id); - const queue = this.#queue.get(message.guild.id); - const connection = joinVoiceChannel({ - channelId: message.member.voice.channel.id, - guildId: message.guild.id, - adapterCreator: message.guild.voiceAdapterCreator - }); - - const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); - connection.subscribe(player); - - queue.connection = connection; - queue.player = player; - queue.voiceChannel = message.member.voice.channel.id; - this.#client.voiceChannel = message.member.voice.channel.id; - queue.guildId = message.guild.id; - - queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { - try { - await Promise.race([ - entersState(connection, VoiceConnectionStatus.Signalling, 5_000), - entersState(connection, VoiceConnectionStatus.Connecting, 5_000), - ]); - } catch (error) { - this.#destroyQueue(queue.guildId); - return "There was an error connecting to the voice channel."; - } - }); - - queue.player.on("error", (err) => { - message.channel.send("An error occurred while playing the track."); - this.#destroyQueue(message.guild.id); - }); - - queue.player.on(AudioPlayerStatus.Idle, () => { - if (queue.loop) queue.queue.push(queue.current); - const queueElement = queue.queue.shift(); - if (queueElement === undefined) { - this.#destroyQueue(message.guild.id); - return { content: "Played all tracks leaving the channel.", announce: true }; - } - this.play(message.guild.id, queueElement); - }); - - this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - return "Started playing track!"; - } - - const queue = this.#queue.get(message.guild.id); - - if (queue.voiceChannel !== message.member.voice.channel.id) { - return "You have to be in the same voice channel as the bot to add new tracks."; - } - - queue.queue.push({ url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); - return ({ embeds: [await this.#createEmbed(info, "Added")], deleteReply: 10, announce: true }); - } - - skip(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to skip tracks."; - - const queueElement = queue.queue.shift(); - - if (queueElement === undefined && !queue.loop) { - if (queue.loop) { - this.play(message.guild.id, queueElement || queue.current); - } else { - this.#destroyQueue(message.guild.id); - } - return { content: "Skipped last track. Leaving channel!", announce: true }; - } else { - this.play(message.guild.id, queueElement || queue.current); - return { content: "Skipped track.", announce: true }; - } - } - - stop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to stop the bot."; - - this.#destroyQueue(message.guild.id); - return { content: "Leaving channel.", announce: true }; - } - - shuffle(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to shuffle the queue."; - - queue.queue.shuffle(); - return { content: "Shuffled the Queue.", announce: true }; - } - - getQueue(guildId) { - return this.#queue.get(guildId); - } - - getCurrent(guildId) { - return this.#queue.get(guildId)?.current; - } - - clearQueue(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to clear the queue."; - - queue.queue.clear(); - return { content: "Cleared queue.", announce: true }; - } - - #channelEmpty(channelId) { - return this.#client.channels.cache.get(channelId)?.members.filter((member) => !member.user.bot).size === 0; - } - - troll(message) { - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return; - queue.queue.clear(); - /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ - this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); - } - - toggleLoop(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to toggle looping."; - - queue.loop = !queue.loop; - if (queue.loop) { - return { content: "Looping is now enabled.", announce: true }; - } else { - return { content: "Looping is now disabled.", announce: true }; - } - } - - pause(message) { - if (message.member.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "There is nothing playing"; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to pause the track"; - - if (queue.player.state.status == "playing") { - queue.player.pause(); - return { content: "The track has been paused", announce: true }; - } else if (queue.player.state.status == "paused") { - return "The track is already paused"; - } - } - - resume(message) { - if (message.member.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild.id); - if (queue === undefined) return "No queue for guild."; - - if (queue.voiceChannel !== message.member.voice.channel.id) - return "You have to be in the same voice channel as the bot to pause"; - - if (queue.player.state.status == "paused") { - queue.player.unpause(); - return { content: "The track has been resumed", announce: true }; - } else if (queue.player.state.status == "playing") { - return "The track is already playing"; - } - } -}; - -async function isAgeRestricted(url) { - try { - (await video_basic_info(url)).video_details; - } catch (err) { - return true; - } - return false; -} diff --git a/music/player.ts.ignore b/music/player.ts similarity index 75% rename from music/player.ts.ignore rename to music/player.ts index 8437f24..77e597a 100644 --- a/music/player.ts.ignore +++ b/music/player.ts @@ -1,8 +1,8 @@ import { GuildMember, Message, BaseChannel } from "discord.js"; import { CommandReturnWithoutString } from "../types/command"; -const { createAudioPlayer, createAudioResource, joinVC, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); -import { stream, video_basic_info, search, yt_validate } from "play-dl"; +const { createAudioPlayer, createAudioResource, joinVoiceChannel, entersState, NoSubscriberBehavior, AudioPlayerStatus, VoiceConnectionStatus } = require("@discordjs/voice"); +import { stream, video_basic_info, search, yt_validate, YouTubeVideo } from "play-dl"; import Client from "../types/client"; import { ImprovedArray } from "sussy-util"; import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } from "discord.js"; @@ -10,24 +10,24 @@ import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, Colors } fr const playerControls = new ActionRowBuilder() .addComponents( new ButtonBuilder() - .setCustomId('command:queue') - .setLabel('☰') + .setCustomId("command:queue") + .setLabel("☰") .setStyle(ButtonStyle.Primary), new ButtonBuilder() - .setCustomId('play_pause') - .setLabel('׀׀') + .setCustomId("play_pause") + .setLabel("׀׀") .setStyle(ButtonStyle.Success), new ButtonBuilder() - .setCustomId('command:stop') - .setLabel('◼') + .setCustomId("command:stop") + .setLabel("◼") .setStyle(ButtonStyle.Danger), new ButtonBuilder() - .setCustomId('command:skip') - .setLabel('>>') + .setCustomId("command:skip") + .setLabel(">>") .setStyle(ButtonStyle.Primary), new ButtonBuilder() - .setCustomId('support') - .setLabel('Support us!') + .setCustomId("support") + .setLabel("Support us!") .setStyle(ButtonStyle.Secondary), ); @@ -50,7 +50,7 @@ module.exports = class Player { this.#client.on("voiceStateUpdate", (oldState, newState) => { const queue = this.getQueue(newState.guild.id); - if (queue === void 0 || oldState.channelId === null) { + if (queue === undefined || oldState.channelId === null) { return; } @@ -61,7 +61,7 @@ module.exports = class Player { } return; } - if (newState.channelId === void 0) { + if (newState.channelId === undefined) { queue.current.channel.send("I have been kicked from the channel."); this.#destroyQueue(newState.guild.id); } @@ -86,9 +86,9 @@ module.exports = class Player { #destroyQueue(guildId: string) { const guildInfo = this.#queue.get(guildId); - if (guildInfo === void 0) return; - if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); + if (guildInfo === undefined) return; + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e; }); } guildInfo.connection.destroy(); this.#queue.delete(guildId); @@ -96,15 +96,15 @@ module.exports = class Player { async play(guildId: string, track: QueueElement) { const guildInfo = this.#queue.get(guildId); - if (guildInfo === void 0) return; + if (guildInfo === undefined) return; guildInfo.current = track; const streamReturn = await stream(track.url); const resource = createAudioResource(streamReturn.stream, { inputType: streamReturn.type }); guildInfo.player.play(resource); - if (guildInfo.lastNowPlayingMessage !== void 0) { - guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e }); + if (guildInfo.lastNowPlayingMessage !== undefined) { + guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e; }); } // @ts-expect-error guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); @@ -119,7 +119,7 @@ module.exports = class Player { .setFooter(this.#client.config.embedFooter(this.#client)); if (info.title) { - embed.setTitle(`${type} track ${info.title}`); + embed.setTitle(`${type} "${info.title}"`); } if (info.thumbnails) { @@ -133,9 +133,11 @@ module.exports = class Player { } async addTrack(message: Message, args: string[]) { - if (message.member!.voice?.channel === void 0 || message.member!.voice?.channel === null) return "Connect to a Voice Channel"; + let startMillis; + let info = false as YouTubeVideo | false; + if (message.member?.voice.channel === undefined || message.member.voice.channel === null) return "Connect to a Voice Channel"; - let videoName = args.map(e => e.trim()).join(" ").trim(); + const videoName = args.map(e => e.trim()).join(" ").trim(); if (videoName === "") return "Please enter the link/name of the track"; @@ -143,31 +145,41 @@ module.exports = class Player { if (videoName.startsWith("https") && yt_validate(videoName) === "video") { url = videoName; } else { + startMillis = Date.now(); const yt_infos = await search(args.join(" "), { limit: 10 }); + console.debug("Search took " + (Date.now() - startMillis) + "ms"); let currentInfo = 0; + startMillis = Date.now(); do { url = yt_infos[currentInfo].url; currentInfo++; - } while (await isAgeRestricted(url) && currentInfo < yt_infos.length); + info = await isNotAgeRestricted(url); + } while (info === false && currentInfo < yt_infos.length); + console.debug("Age check took " + (Date.now() - startMillis) + "ms"); } - let info; - try { - info = (await video_basic_info(url)).video_details; - } catch (err) { + startMillis = Date.now(); + if (info === false) { + try { + info = (await video_basic_info(url)).video_details; + } catch (err) { } } - if (info === void 0) { + if (info === undefined) { if (this.#queue.get(message.guild!.id)?.queue.length === 0) return; - let returnValue = this.skip(message) as CommandReturnWithoutString; + const returnValue = this.skip(message) as CommandReturnWithoutString; returnValue!.content = "Can't play tracks requiring age verification! Skipping..."; return returnValue; } + info = info as YouTubeVideo; + + console.debug("Getting info took " + (Date.now() - startMillis) + "ms"); + if (!this.#queue.has(message.guild!.id)) { this.#newQueue(message.guild!.id); const queue = this.#queue.get(message.guild!.id); - const connection = joinVC({ + const connection = joinVoiceChannel({ channelId: message.member!.voice.channel.id, guildId: message.guild!.id, adapterCreator: message.guild!.voiceAdapterCreator @@ -202,7 +214,7 @@ module.exports = class Player { queue.player.on(AudioPlayerStatus.Idle, () => { if (queue.loop) queue.queue.push(queue.current); const queueElement = queue.queue.shift(); - if (queueElement === void 0) { + if (queueElement === undefined) { this.#destroyQueue(message.guild!.id); return { content: "Played all tracks leaving the channel.", announce: true }; } @@ -226,16 +238,16 @@ module.exports = class Player { } skip(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; + if (queue === undefined) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to skip tracks."; const queueElement = queue.queue.shift(); - if (queueElement === void 0 && !queue.loop) { + if (queueElement === undefined && !queue.loop) { if (queue.loop) { this.play(message.guild!.id, queueElement || queue.current); } else { @@ -249,9 +261,9 @@ module.exports = class Player { } stop(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; + if (queue === undefined) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to stop the bot."; @@ -261,9 +273,9 @@ module.exports = class Player { } shuffle(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; + if (queue === undefined) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to shuffle the queue."; @@ -281,9 +293,9 @@ module.exports = class Player { } clearQueue(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0 || queue.queue.length == 0) return "No queue for guild."; + if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to clear the queue."; @@ -299,7 +311,7 @@ module.exports = class Player { troll(message: Message) { const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return; + if (queue === undefined) return; queue.queue.clear(); /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ // @ts-expect-error // I gotta make a type for this @@ -307,9 +319,9 @@ module.exports = class Player { } toggleLoop(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; + if (queue === undefined) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to toggle looping."; @@ -323,9 +335,9 @@ module.exports = class Player { } pause(message: Message) { - if (message.member!.voice?.channel === void 0) return "You have to be in the same voice channel as the bot to pause the track"; + if (message.member!.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "There is nothing playing"; + if (queue === undefined) return "There is nothing playing"; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to pause the track"; @@ -339,9 +351,9 @@ module.exports = class Player { } resume(message: Message) { - if (message.member!.voice?.channel === void 0) return "Connect to a Voice Channel"; + if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; const queue = this.#queue.get(message.guild!.id); - if (queue === void 0) return "No queue for guild."; + if (queue === undefined) return "No queue for guild."; if (queue.voiceChannel !== message.member!.voice.channel!.id) return "You have to be in the same voice channel as the bot to pause"; @@ -355,13 +367,15 @@ module.exports = class Player { } }; -async function isAgeRestricted(url: string) { +async function isNotAgeRestricted(url: string) { + let info; try { - (await video_basic_info(url)).video_details; + info = (await video_basic_info(url)).video_details; } catch (err) { - return true; + return false; } - return false; + if (info === undefined) return false; + return info; } type QueueElement = { diff --git a/schemas/user.ts b/schemas/user.ts index 946c29b..954020f 100644 --- a/schemas/user.ts +++ b/schemas/user.ts @@ -1,4 +1,4 @@ -const { Schema, model } = require(`mongoose`); +const { Schema, model } = require("mongoose"); const userSchema = new Schema({ _id: Schema.Types.ObjectId, diff --git a/selectMenus/general/help.ts b/selectMenus/general/help.ts index 6f8abdb..39f9d05 100644 --- a/selectMenus/general/help.ts +++ b/selectMenus/general/help.ts @@ -1,7 +1,7 @@ import { Component } from "../../types/command"; module.exports = { - run(client, interaction, args, guildData, userData) { + run(_client, _interaction, args, _guildData, _userData) { console.info("helpmenu.js", args); return "This command is currently WIP but I already known that you selected " + args[0] + "! MAGIC!"; } diff --git a/tslint-to-eslint-config.log b/tslint-to-eslint-config.log deleted file mode 100644 index 99e8ce9..0000000 --- a/tslint-to-eslint-config.log +++ /dev/null @@ -1,4 +0,0 @@ -1 ESLint rule behaves differently from its TSLint counterpart: - * @typescript-eslint/no-unused-expressions: - - The TSLint optional config "allow-new" is the default ESLint behavior and will no longer be ignored. - diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 059fff1..0000000 --- a/tslint.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "rules": { - "no-unused-expression": true, - "no-duplicate-variable": true, - "class-name": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": true - }, - "defaultSeverity": "warning" -} \ No newline at end of file diff --git a/types/client.ts b/types/client.ts index 172520b..ee6f00e 100644 --- a/types/client.ts +++ b/types/client.ts @@ -1,18 +1,21 @@ import { Client as DiscordClient, Collection } from "discord.js"; import { Command } from "./command"; -// @ts-ignore: Unreachable code error +// @ts-expect-error // I wrote it so I can have it as a js or ts file // FIXME import Player from "../music/player"; import { connection } from "mongoose"; -export default interface Client extends DiscordClient { +interface Client extends DiscordClient { commands: Collection; player: Player; commandCooldowns: Collection>; config: ClientConfig; + // eslint-disable-next-line @typescript-eslint/ban-types functions?: Function[]; connection: typeof connection; } +export default Client; + type ClientConfig = { token: string; prefix: string; diff --git a/types/command.ts b/types/command.ts index a47d537..eea2a2e 100644 --- a/types/command.ts +++ b/types/command.ts @@ -1,5 +1,6 @@ import { CommandInteraction, ApplicationCommandOption, CacheType, Message, InteractionReplyOptions, MessageReplyOptions } from "discord.js"; import Client from "./client"; +import { UserData, GuildData } from "./data"; export interface Command { ignore?: boolean; @@ -10,7 +11,7 @@ export interface Command { default_member_permissions?: string; commandOptions?: CommandOptions; category?: string; - run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: any, userData: any, isInteraction: boolean) => CommandReturns; + run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: GuildData, userData: UserData, isInteraction: boolean) => CommandReturns; } interface CommandOptions { diff --git a/types/data.ts b/types/data.ts new file mode 100644 index 0000000..6fa4f26 --- /dev/null +++ b/types/data.ts @@ -0,0 +1,5 @@ +import userModel from "../schemas/user"; +import guildModel from "../schemas/guild"; + +export type UserData = typeof userModel; +export type GuildData = typeof guildModel; diff --git a/www/index.ts b/www/index.ts index 75f8910..e4429ee 100644 --- a/www/index.ts +++ b/www/index.ts @@ -15,7 +15,7 @@ for (const file of files) { } module.exports = { - startServer: (client: Client, port: number, callback: Function) => { + startServer: (client: Client, port: number, callback: () => unknown) => { app.listen(port, callback); } -} \ No newline at end of file +}; \ No newline at end of file From 49c4e465b2b329dc7d1f2aac242f0486e7fe48d1 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:09:17 +0100 Subject: [PATCH 16/28] fixed some errors and warnings --- commands/economy/beg.ts | 11 +- commands/economy/bet.ts | 4 +- commands/economy/deposit.ts | 4 +- commands/economy/job.ts | 2 +- commands/economy/withdraw.ts | 2 +- commands/economy/work.ts | 2 +- commands/moderation/set-counter-channel.ts | 1 + commands/moderation/set-goodbye-channel.ts | 1 + commands/moderation/set-welcome-channel.ts | 1 + commands/music/play.ts | 2 - functions/counter.ts | 2 +- functions/executeCommand.ts | 5 +- functions/getGuildData.ts | 2 +- functions/getUserData.ts | 3 +- music/player.ts | 127 ++++++++++++--------- schemas/guild.ts | 30 ++++- schemas/user.ts | 20 +++- types/data.ts | 8 +- www/routes/logo.ts | 2 +- 19 files changed, 149 insertions(+), 80 deletions(-) diff --git a/commands/economy/beg.ts b/commands/economy/beg.ts index 0b261ec..717c378 100644 --- a/commands/economy/beg.ts +++ b/commands/economy/beg.ts @@ -5,11 +5,10 @@ import messages from "../../resources/messages.json"; import { UserData } from "../../types/data"; module.exports = { - ignore: true, // the messages is kinda broken - //TODO: fix the messages - description: "Beg to earn money", - cooldown: 60, + commandOptions: { + cooldown: 60 + }, run(_client, message, _args, _guildData, userData, _isSlashCommand) { if (userData.economy?.wallet < 200) @@ -18,12 +17,12 @@ module.exports = { userData.economy.wallet += earned; userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: UserData) => { if (err) console.error(err); - if (!data) return "Error: User not found."; + if (!data) return { content: "Error: User not found.", success: false }; }); userData.level.xp += 2; userList.findByIdAndUpdate(userData._id, { level: userData.level }, (err: Error, data: UserData) => { if (err) console.error(err); - if (!data) return "Error: User not found."; + if (!data) return { content: "Error: User not found.", success: false }; }); if (!(Math.floor(userData.level.xp / 50 /*0.5*/) === (Math.floor((userData.level.xp - 5) / 50) /*0.6*/))) { message.channel?.send(`<@${userData.userId}>` + " just levelled up!"); diff --git a/commands/economy/bet.ts b/commands/economy/bet.ts index c69d103..080f0d2 100644 --- a/commands/economy/bet.ts +++ b/commands/economy/bet.ts @@ -24,7 +24,7 @@ module.exports = { } ); } - else if (args[0] > userData.economy.wallet) { + else if (+args[0] > userData.economy.wallet) { embed.addFields( { name: "Bet failed!", @@ -48,7 +48,7 @@ module.exports = { ); break; default: - userData.economy.wallet += args[0]; + userData.economy.wallet += +args[0]; embed.addFields( { name: "You won!", diff --git a/commands/economy/deposit.ts b/commands/economy/deposit.ts index 7746193..92fc157 100644 --- a/commands/economy/deposit.ts +++ b/commands/economy/deposit.ts @@ -2,7 +2,7 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; const { IsSomething } = require("sussy-util"); -const users = require("../../schemas/user"); +import users from "../../schemas/user"; module.exports = { description: "Deposit money into your bank account", @@ -20,6 +20,8 @@ module.exports = { run: (_client, _message, args, _guildInfo, userInfo) => { if (!args[0]) return "Please provide the amount you want to deposit."; + if (userInfo === null) return "Error: User not found."; + if (userInfo.economy === null) return "Error: User not found."; const current = userInfo.economy; let moneys = current.wallet; diff --git a/commands/economy/job.ts b/commands/economy/job.ts index 54f42dd..6ea4ee8 100644 --- a/commands/economy/job.ts +++ b/commands/economy/job.ts @@ -77,7 +77,7 @@ module.exports = { return "Level too low for this job"; } - userData.jobinfo.id = args[0]; + userData.jobinfo.id = +args[0]; userList.findByIdAndUpdate(userData._id, { jobinfo: userData.jobinfo }, (err: Error, data: unknown) => { if (err) console.error(err); if (!data) return "Error: User not found."; diff --git a/commands/economy/withdraw.ts b/commands/economy/withdraw.ts index 14a619f..04def04 100644 --- a/commands/economy/withdraw.ts +++ b/commands/economy/withdraw.ts @@ -17,7 +17,7 @@ module.exports = { run(_client, _message, args, _guildData, userData, _isSlashCommand) { let amount = args[0]; if (amount && IsSomething.isNumber(amount)) { - if (amount > userData.economy.bank) amount = userData.economy.bank; + if (+amount > userData.economy.bank) amount = "" + userData.economy.bank; userData.economy.bank -= +amount; userData.economy.wallet += +amount; userList.findByIdAndUpdate(userData._id, { economy: userData.economy }, (err: Error, data: UserData) => { diff --git a/commands/economy/work.ts b/commands/economy/work.ts index 154e859..d7f6332 100644 --- a/commands/economy/work.ts +++ b/commands/economy/work.ts @@ -1,7 +1,7 @@ import { Command } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; -const userList = require("../../schemas/user"); +import userList from "../../schemas/user"; const jobs = require("./resources/jobs.json").jobs; module.exports = { diff --git a/commands/moderation/set-counter-channel.ts b/commands/moderation/set-counter-channel.ts index 53d41f2..823341c 100644 --- a/commands/moderation/set-counter-channel.ts +++ b/commands/moderation/set-counter-channel.ts @@ -24,6 +24,7 @@ module.exports = { async run(_client, message, args, guildData, _userData, _isSlashCommand) { let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; + if (guildData === null) return "Error: Guild not found."; const current = guildData.channels; current.counter = channel.id; diff --git a/commands/moderation/set-goodbye-channel.ts b/commands/moderation/set-goodbye-channel.ts index 525c29a..b5a19e3 100644 --- a/commands/moderation/set-goodbye-channel.ts +++ b/commands/moderation/set-goodbye-channel.ts @@ -24,6 +24,7 @@ module.exports = { async run(_client, message, args, guildData, _userData, _isSlashCommand) { let channel = global.functions.getChannelFromMention(message.guild, args[0]); if (channel === undefined) channel = message.channel; + if (guildData === null) return "Error: Guild not found."; const current = guildData.channels; current.goodbye = channel.id; diff --git a/commands/moderation/set-welcome-channel.ts b/commands/moderation/set-welcome-channel.ts index 557354e..2357dde 100644 --- a/commands/moderation/set-welcome-channel.ts +++ b/commands/moderation/set-welcome-channel.ts @@ -22,6 +22,7 @@ module.exports = { default_member_permissions: permissionStrings.ManageChannels, async run(_client, message, args, guildData, _userData, _isSlashCommand) { + if (guildData === null) return "Error: Guild not found."; let channel = global.functions.getChannelFromMention(message.guild, args[0]); channel ||= message.channel; const current = guildData.channels; diff --git a/commands/music/play.ts b/commands/music/play.ts index 708017c..e81f767 100644 --- a/commands/music/play.ts +++ b/commands/music/play.ts @@ -18,9 +18,7 @@ module.exports = { async run(client, message, args, _guildData, _userData, _isSlashCommand) { // @ts-expect-error // cause it's getting caught anyway try { message.suppressEmbeds(true); } catch (e) { } - const startMillis = Date.now(); const returnVar = await client.player.addTrack(message, args); - console.debug(`Command ${this.name} took ${Date.now() - startMillis}ms to execute`); return returnVar; } } as Command; diff --git a/functions/counter.ts b/functions/counter.ts index 2267870..0a548f9 100644 --- a/functions/counter.ts +++ b/functions/counter.ts @@ -7,7 +7,7 @@ module.exports = (message: Message, guildData: GuildData) => { if (guildData?.channels?.counter === undefined) return; if (!(guildData.channels.counter === message.channel.id)) return false; const current = guildData.counter.current; - if (message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) + if (+message.content.toLowerCase() == (current + 1) && message.author.id != guildData.counter.lastId) guilds.findByIdAndUpdate(guildData._id, { counter: { current: current + 1, lastId: message.author.id } }, (err: Error, data: GuildData) => { if (err) console.error(err); (err); diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index ce20fad..575324e 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -56,9 +56,10 @@ module.exports = async (command: Command, client: Client, interaction: Mes try { if (command.commandOptions?.guildOnly && interaction.guildId === null) return interaction.reply("This command can only be used in a server."); - let guildData; + let guildData = null; if (interaction.guild) guildData = await getGuildData(interaction.guild.id); + if (guildData === undefined) guildData = null; const userData = await getUserData(interaction.author.id); @@ -77,7 +78,7 @@ module.exports = async (command: Command, client: Client, interaction: Mes // @ts-expect-error // cause if it's undefined, it's not doing anything anyway const success = returnValue.success || command.commandOptions?.defaultReturn?.success; - if (success) { + if (!(success === false) && command.commandOptions?.cooldown) { if (returnValue.setCooldown) returnValue.setCooldown.push(command); else diff --git a/functions/getGuildData.ts b/functions/getGuildData.ts index b83deb8..beee4f7 100644 --- a/functions/getGuildData.ts +++ b/functions/getGuildData.ts @@ -3,7 +3,7 @@ import addGuildDocument from "./addGuildDocument"; import { GuildData } from "../types/data"; export default async (guildId: string): Promise => { - let guildData = await guildModel.findOne({ guildId: guildId }); + let guildData = await guildModel.findOne({ guildId: guildId }) as GuildData; if (!guildData) { addGuildDocument(guildId); guildData = await guildModel.findOne({ guildId: guildId }); diff --git a/functions/getUserData.ts b/functions/getUserData.ts index a498481..527dd08 100644 --- a/functions/getUserData.ts +++ b/functions/getUserData.ts @@ -3,10 +3,11 @@ import addUserDocument from "./addUserDocument"; import { UserData } from "../types/data"; export default async (userId: string): Promise => { - let userData = await userModel.findOne({ userId: userId }); + let userData = await userModel.findOne({ userId: userId }) as UserData | null; if (!userData) { addUserDocument(userId); userData = await userModel.findOne({ userId: userId }); } + userData = userData as UserData; return userData; }; diff --git a/music/player.ts b/music/player.ts index 77e597a..e050016 100644 --- a/music/player.ts +++ b/music/player.ts @@ -106,7 +106,7 @@ module.exports = class Player { if (guildInfo.lastNowPlayingMessage !== undefined) { guildInfo.lastNowPlayingMessage.delete().catch((e: Error) => { e; }); } - // @ts-expect-error + // @ts-expect-error // MiMiMiMiMi i don't care guildInfo.lastNowPlayingMessage = await track.channel.send({ embeds: [await this.#createEmbed(track, "Now playing")], components: [playerControls] }); } @@ -115,7 +115,7 @@ module.exports = class Player { .setURL(info.url) .setColor(Colors.Red) .setTimestamp(new Date()) - // @ts-expect-error + // @ts-expect-error // something wrong here, idfk .setFooter(this.#client.config.embedFooter(this.#client)); if (info.title) { @@ -133,8 +133,9 @@ module.exports = class Player { } async addTrack(message: Message, args: string[]) { - let startMillis; let info = false as YouTubeVideo | false; + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); if (message.member?.voice.channel === undefined || message.member.voice.channel === null) return "Connect to a Voice Channel"; const videoName = args.map(e => e.trim()).join(" ").trim(); @@ -145,44 +146,37 @@ module.exports = class Player { if (videoName.startsWith("https") && yt_validate(videoName) === "video") { url = videoName; } else { - startMillis = Date.now(); const yt_infos = await search(args.join(" "), { limit: 10 }); - console.debug("Search took " + (Date.now() - startMillis) + "ms"); let currentInfo = 0; - startMillis = Date.now(); do { url = yt_infos[currentInfo].url; currentInfo++; info = await isNotAgeRestricted(url); } while (info === false && currentInfo < yt_infos.length); - console.debug("Age check took " + (Date.now() - startMillis) + "ms"); } - startMillis = Date.now(); - if (info === false) { try { info = (await video_basic_info(url)).video_details; } catch (err) { } } if (info === undefined) { - if (this.#queue.get(message.guild!.id)?.queue.length === 0) return; + if (this.#queue.get(message.guild.id)?.queue.length === 0) return; const returnValue = this.skip(message) as CommandReturnWithoutString; - returnValue!.content = "Can't play tracks requiring age verification! Skipping..."; + if (returnValue === null) throw new Error("CommandReturn is null"); + returnValue.content = "Can't play tracks requiring age verification! Skipping..."; return returnValue; } info = info as YouTubeVideo; - console.debug("Getting info took " + (Date.now() - startMillis) + "ms"); - - if (!this.#queue.has(message.guild!.id)) { - this.#newQueue(message.guild!.id); - const queue = this.#queue.get(message.guild!.id); + if (!this.#queue.has(message.guild.id)) { + this.#newQueue(message.guild.id); + const queue = this.#queue.get(message.guild.id); const connection = joinVoiceChannel({ - channelId: message.member!.voice.channel.id, - guildId: message.guild!.id, - adapterCreator: message.guild!.voiceAdapterCreator + channelId: message.member.voice.channel.id, + guildId: message.guild.id, + adapterCreator: message.guild.voiceAdapterCreator }); const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } }); @@ -190,8 +184,8 @@ module.exports = class Player { queue.connection = connection; queue.player = player; - queue.voiceChannel = message.member!.voice.channel.id; - queue.guildId = message.guild!.id; + queue.voiceChannel = message.member.voice.channel.id; + queue.guildId = message.guild.id; queue.connection.on(VoiceConnectionStatus.Disconnected, async () => { try { @@ -206,29 +200,32 @@ module.exports = class Player { }); queue.player.on("error", (err: Error) => { + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); message.channel.send("An error occurred while playing the track."); - this.#destroyQueue(message.guild!.id); + this.#destroyQueue(message.guild.id); err; }); queue.player.on(AudioPlayerStatus.Idle, () => { + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); if (queue.loop) queue.queue.push(queue.current); const queueElement = queue.queue.shift(); if (queueElement === undefined) { - this.#destroyQueue(message.guild!.id); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + this.#destroyQueue(message.guild.id); return { content: "Played all tracks leaving the channel.", announce: true }; } - this.play(message.guild!.id, queueElement); + this.play(message.guild.id, queueElement); }); // @ts-expect-error // I gotta make a type for this - this.play(message.guild!.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); + this.play(message.guild.id, { url: url, channel: message.channel, title: info.title, duration: info.durationRaw, thumbnails: info.thumbnails }); return "Started playing track!"; } - const queue = this.#queue.get(message.guild!.id); + const queue = this.#queue.get(message.guild.id); - if (queue.voiceChannel !== message.member!.voice.channel.id) { + if (queue.voiceChannel !== message.member.voice.channel.id) { return "You have to be in the same voice channel as the bot to add new tracks."; } @@ -238,46 +235,54 @@ module.exports = class Player { } skip(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + if (message.member.voice?.channel === null || message.member.voice.channel === undefined) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to skip tracks."; const queueElement = queue.queue.shift(); if (queueElement === undefined && !queue.loop) { if (queue.loop) { - this.play(message.guild!.id, queueElement || queue.current); + this.play(message.guild.id, queueElement || queue.current); } else { - this.#destroyQueue(message.guild!.id); + this.#destroyQueue(message.guild.id); } return { content: "Skipped last track. Leaving channel!", announce: true }; } else { - this.play(message.guild!.id, queueElement || queue.current); + this.play(message.guild.id, queueElement || queue.current); return { content: "Skipped track.", announce: true }; } } stop(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to stop the bot."; - this.#destroyQueue(message.guild!.id); + this.#destroyQueue(message.guild.id); return { content: "Leaving channel.", announce: true }; } shuffle(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to shuffle the queue."; queue.queue.shuffle(); @@ -293,11 +298,14 @@ module.exports = class Player { } clearQueue(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined || queue.queue.length == 0) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to clear the queue."; queue.queue.clear(); @@ -310,20 +318,24 @@ module.exports = class Player { } troll(message: Message) { - const queue = this.#queue.get(message.guild!.id); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return; queue.queue.clear(); /* Playing Never Gonna Give You Up bc we do miniscule amounts of trolling */ // @ts-expect-error // I gotta make a type for this - this.play(message.guild!.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); + this.play(message.guild.id, { url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ", channel: message.channel, title: "Rick Astley - Never Gonna Give You Up (Official Music Video)", duration: "3:32" }); } toggleLoop(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to toggle looping."; queue.loop = !queue.loop; @@ -335,11 +347,14 @@ module.exports = class Player { } pause(message: Message) { - if (message.member!.voice?.channel === undefined) return "You have to be in the same voice channel as the bot to pause the track"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "There is nothing playing"; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to pause the track"; if (queue.player.state.status == "playing") { @@ -351,11 +366,14 @@ module.exports = class Player { } resume(message: Message) { - if (message.member!.voice?.channel === undefined) return "Connect to a Voice Channel"; - const queue = this.#queue.get(message.guild!.id); + if (message.member === null) throw new Error("Member is null"); + if (message.guild === null) throw new Error("Member is not using the command in a guild!"); + + if (message.member.voice?.channel === undefined || message.member.voice?.channel === null) return "Connect to a Voice Channel"; + const queue = this.#queue.get(message.guild.id); if (queue === undefined) return "No queue for guild."; - if (queue.voiceChannel !== message.member!.voice.channel!.id) + if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to pause"; if (queue.player.state.status == "paused") { @@ -383,5 +401,6 @@ type QueueElement = { channel: BaseChannel; title: string; duration?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- idk what type this is thumbnails: any[]; }; \ No newline at end of file diff --git a/schemas/guild.ts b/schemas/guild.ts index d0ac9e2..d7cb8e7 100644 --- a/schemas/guild.ts +++ b/schemas/guild.ts @@ -1,4 +1,4 @@ -const { Schema, model } = require("mongoose"); +import { Schema, model } from "mongoose"; const guildSchema = new Schema({ _id: Schema.Types.ObjectId, @@ -29,3 +29,31 @@ const guildSchema = new Schema({ }); export default model("guild", guildSchema, "guilds"); + +export interface GuildScheme { + _id: Schema.Types.ObjectId; + guildId: string; + + channels: { + welcome: string; + goodbye: string; + counter: string; + + allowed: string[]; + }; + + counter: { + current: number; + lastId: string; + }; + + warns: { + userId: string; + count: number; + }[]; + + tempBans: { + userId: string; + endDate: Date; + }[]; +} diff --git a/schemas/user.ts b/schemas/user.ts index 954020f..18da633 100644 --- a/schemas/user.ts +++ b/schemas/user.ts @@ -1,4 +1,4 @@ -const { Schema, model } = require("mongoose"); +import { Schema, model } from "mongoose"; const userSchema = new Schema({ _id: Schema.Types.ObjectId, @@ -19,3 +19,21 @@ const userSchema = new Schema({ }); export default model("user", userSchema, "users"); + +export interface UserScheme { + _id: Schema.Types.ObjectId; + userId: string; + + level: { + xp: number; + }; + + economy: { + wallet: number; + bank: number; + }; + + jobinfo: { + id: number; + }; +} diff --git a/types/data.ts b/types/data.ts index 6fa4f26..fbcd80f 100644 --- a/types/data.ts +++ b/types/data.ts @@ -1,5 +1,5 @@ -import userModel from "../schemas/user"; -import guildModel from "../schemas/guild"; +import { UserScheme } from "../schemas/user"; +import { GuildScheme } from "../schemas/guild"; -export type UserData = typeof userModel; -export type GuildData = typeof guildModel; +export type UserData = UserScheme; +export type GuildData = GuildScheme | null; diff --git a/www/routes/logo.ts b/www/routes/logo.ts index e8a1570..07b0675 100644 --- a/www/routes/logo.ts +++ b/www/routes/logo.ts @@ -1,4 +1,4 @@ -const { loadImage, createCanvas } = require("canvas"); +import { loadImage, createCanvas } from "canvas"; const express = require("express"); const path = require("path"); From 4a5c7ef1192718d8cb1aab6ee4866b48f811de8f Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:42:03 +0100 Subject: [PATCH 17/28] dirty fix for console object --- events/discord/ready.ts | 1 - events/mongodb/connected.ts | 1 - index.ts | 11 +++++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/events/discord/ready.ts b/events/discord/ready.ts index 7954996..9872dd0 100644 --- a/events/discord/ready.ts +++ b/events/discord/ready.ts @@ -2,6 +2,5 @@ import Client from "../../types/client"; module.exports = (client: Client) => { client.user.setActivity(`${client.config.prefix}help`); - // @ts-expect-error // it really does... console.success("Bot is ready!"); }; diff --git a/events/mongodb/connected.ts b/events/mongodb/connected.ts index 4cda6c8..a95c578 100644 --- a/events/mongodb/connected.ts +++ b/events/mongodb/connected.ts @@ -1,6 +1,5 @@ import { Connection } from "mongoose"; module.exports = (_client: Connection) => { - // @ts-expect-error // gotta add success to the console type console.success("MongoDB connection is ready!"); } diff --git a/index.ts b/index.ts index c9fc6f3..1719973 100644 --- a/index.ts +++ b/index.ts @@ -14,6 +14,13 @@ set("strictQuery", false); require("better-cl").setup(console, [], "./logs"); + +declare global { + interface Console { + success: (message: string) => void; + } +} + console.clear(); const client = new Client({ @@ -79,11 +86,11 @@ export default client; /* Logging the bot in. */ client.login(process.env.TOKEN); +console.info("Logging the bot in..."); /* Connect to the mongodb database */ connect(process.env.MONGODB); /* Starting the Webserver */ -console.log("Starting webserver..."); -// @ts-expect-error // TODO: I gotta find a way to add functions to the console object +console.info("Starting webserver..."); require("./www/index").startServer(client, process.env.PORT, () => console.success("Webserver ready!")); // makes sure the bot doesn't crash From d8129331d3f8800d364301583398d6d9195779b6 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:59:24 +0100 Subject: [PATCH 18/28] fixed a lot of bugs --- Commands.md | 42 +++++++++--------- Issues.md | 4 +- commands/economy/resetBalance.ts | 5 ++- commands/economy/resetLevel.ts | 5 ++- commands/economy/withdraw.ts | 3 +- commands/general/inviteBot.ts | 15 ++++++- commands/music/clearQueue.ts | 3 +- commands/music/loop.ts | 3 +- commands/music/nowPlaying.ts | 3 +- commands/music/pause.ts | 3 +- commands/music/play.ts | 5 ++- commands/music/queue.ts | 3 +- commands/music/remove.ts | 76 ++++++++++++++++++++++++++++++++ commands/music/resume.ts | 3 +- commands/music/shuffle.ts | 3 +- commands/music/skip.ts | 3 +- commands/music/stop.ts | 3 +- commands/music/troll.ts | 5 ++- events/discord/messageCreate.ts | 13 +++--- functions/executeCommand.ts | 38 +++++++++------- index.ts | 20 +++++---- music/player.ts | 64 ++++++++++++++++++--------- 22 files changed, 234 insertions(+), 88 deletions(-) create mode 100644 commands/music/remove.ts diff --git a/Commands.md b/Commands.md index 92072a0..191cfef 100644 --- a/Commands.md +++ b/Commands.md @@ -3,34 +3,34 @@ ## Economy - [x] balance -- [ ] beg +- [x] beg - [x] bet - [x] deposit - [x] job - [x] level -- [x] resetBalance -- [x] resetLevel +- [ ] resetBalance +- [ ] resetLevel - [x] search - [x] withdraw - [x] work ## Games -- [x] coinflip -- [x] numberGuess +- [ ] coinflip +- [ ] numberGuess ## General - [ ] help -- [x] info -- [x] invite -- [x] inviteBot -- [x] serverInfo -- [x] userInfo +- [ ] info +- [ ] invite +- [ ] inviteBot +- [ ] serverInfo +- [ ] userInfo ## Moderation -- [x] clear +- [ ] clear - [ ] lock - [ ] nickname - [ ] prepare @@ -45,15 +45,15 @@ ## Music -- [x] clear-queue -- [x] loop -- [x] nowPlaying -- [x] pause -- [x] play -- [x] queue +- [ ] clear-queue +- [ ] loop +- [ ] nowPlaying +- [ ] pause +- [ ] play +- [ ] queue COMING SOON! - [ ] remove -- [x] resume -- [x] shuffle -- [x] skip -- [x] stop +- [ ] resume +- [ ] shuffle +- [ ] skip +- [ ] stop - [ ] troll diff --git a/Issues.md b/Issues.md index 120d222..d96d48c 100644 --- a/Issues.md +++ b/Issues.md @@ -19,7 +19,7 @@ - [ ] make a leaderboard command - [x] coinflip returns nothing - [x] coinflip has no right to exist in the current state -- [ ] clear works only when deleting under 50 messages, else it times out +- [x] clear works only when deleting under 50 messages, else it times out - [ ] all set-*-channel commands are broken as they don't work with slash commands - [ ] tempban "guildInfo" is not defined - [ ] unban doesn't work at all @@ -56,3 +56,5 @@ message_reference: Unknown message - [x] search gives you a cooldown even when you didn't search anything - [ ] job doesn't display which level is required to get the job - [ ] coinflip "You are victorious!"... Like WTF?! Mb think 5 secs before writing that +- [ ] when adding videos via an url, the bot doesn't check if the url is valid, so the queue element could be undefined, when trying to skip and it's undefined the bot prints an error to the console and doesn't skip the song, when asked to skip again it skips to the song after the undefined one +- [ ] when joining from another channel, the bot says "Leaving channel because it is empty" and leaves the channel diff --git a/commands/economy/resetBalance.ts b/commands/economy/resetBalance.ts index 87ce2fb..8dbb5e2 100644 --- a/commands/economy/resetBalance.ts +++ b/commands/economy/resetBalance.ts @@ -1,3 +1,4 @@ +import { BaseInteraction, DMChannel } from "discord.js"; import { Command } from "../../types/command"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); @@ -6,7 +7,7 @@ module.exports = { description: "Clears your balance", aliases: ["clb", "clearbalance", "resetbalance", "rb", "resetbal", "clearbal"], - run(client, _message, _args, _guildData, _userData, isInteraction) { + run(client, message, _args, _guildData, _userData, _isInteraction) { const embed = new EmbedBuilder() .setTitle("Reset Balance") .setDescription("Are you sure you want to reset your balance?") @@ -14,7 +15,7 @@ module.exports = { // @ts-expect-error // TODO: Fix this .setFooter(client.config.embedFooter(client)); - if (isInteraction) { + if (message instanceof BaseInteraction || message.channel instanceof DMChannel) { const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() diff --git a/commands/economy/resetLevel.ts b/commands/economy/resetLevel.ts index eb21774..2829a60 100644 --- a/commands/economy/resetLevel.ts +++ b/commands/economy/resetLevel.ts @@ -1,3 +1,4 @@ +import { BaseInteraction, DMChannel } from "discord.js"; import { Command } from "../../types/command"; const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = require("discord.js"); @@ -6,7 +7,7 @@ module.exports = { description: "Clears your level", aliases: ["cll", "clearlevel", "resetlevel", "rl", "resetlvl", "clearlvl"], - run(client, _message, _args, _guildData, _userData, isInteraction) { + run(client, message, _args, _guildData, _userData, _isInteraction) { const embed = new EmbedBuilder() .setTitle("Reset Level") .setDescription("Are you sure you want to reset your level?") @@ -14,7 +15,7 @@ module.exports = { // @ts-expect-error // something wrong here, idfk .setFooter(client.config.embedFooter(client)); - if (isInteraction) { + if (message instanceof BaseInteraction || message.channel instanceof DMChannel) { const row = new ActionRowBuilder() .addComponents( new ButtonBuilder() diff --git a/commands/economy/withdraw.ts b/commands/economy/withdraw.ts index 04def04..a831fdd 100644 --- a/commands/economy/withdraw.ts +++ b/commands/economy/withdraw.ts @@ -3,7 +3,8 @@ import { ApplicationCommandOptionType } from "discord.js"; import { UserData } from "../../types/data"; const { IsSomething } = require("sussy-util"); -const userList = require("../../schemas/user"); +import userList from "../../schemas/user"; + module.exports = { description: "Withdraw money from your bank account", aliases: ["with", "wth"], diff --git a/commands/general/inviteBot.ts b/commands/general/inviteBot.ts index c56bad4..51de7bb 100644 --- a/commands/general/inviteBot.ts +++ b/commands/general/inviteBot.ts @@ -1,9 +1,22 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; import { Command } from "../../types/command"; module.exports = { description: "Sends the invite link of the bot", async run(client, _message, _args, _guildData, _userData, _isSlashCommand) { - return { content: "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands" }; + const inviteLink = "https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=8&scope=bot%20applications.commands"; + const inviteButtonRow = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel("Invite me!") + .setStyle(ButtonStyle.Link) + .setURL(inviteLink), + new ButtonBuilder() + .setCustomId("support") + .setLabel("Support me!") + .setStyle(ButtonStyle.Success), + ); + return { content: `Thanks for using ${client.user.tag.replace(/#.*/, "")}!`, components: [inviteButtonRow] }; } } as Command; diff --git a/commands/music/clearQueue.ts b/commands/music/clearQueue.ts index 5829642..0b66685 100644 --- a/commands/music/clearQueue.ts +++ b/commands/music/clearQueue.ts @@ -3,7 +3,8 @@ import { Command } from "../../types/command"; module.exports = { description: "Clears the song queue.", commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/loop.ts b/commands/music/loop.ts index 601a61c..d5731d0 100644 --- a/commands/music/loop.ts +++ b/commands/music/loop.ts @@ -4,7 +4,8 @@ module.exports = { description: "Loops the current queue.", aliases: ["repeat"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { return client.player.toggleLoop(message); diff --git a/commands/music/nowPlaying.ts b/commands/music/nowPlaying.ts index 423f173..636f82c 100644 --- a/commands/music/nowPlaying.ts +++ b/commands/music/nowPlaying.ts @@ -4,7 +4,8 @@ module.exports = { description: "Shows the current song", aliases: ["current"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/pause.ts b/commands/music/pause.ts index 8683db7..eaaa008 100644 --- a/commands/music/pause.ts +++ b/commands/music/pause.ts @@ -4,7 +4,8 @@ module.exports = { aliases: [], description: "Pauses the current song", commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/play.ts b/commands/music/play.ts index e81f767..8dde9c7 100644 --- a/commands/music/play.ts +++ b/commands/music/play.ts @@ -4,7 +4,10 @@ import { ApplicationCommandOptionType } from "discord.js"; module.exports = { description: "Adds a song to the queue", aliases: ["p"], - connectedToVC: true, + commandOptions: { + connectedToVC: true, + guildOnly: true + }, options: [ { diff --git a/commands/music/queue.ts b/commands/music/queue.ts index b23f96f..9f043a4 100644 --- a/commands/music/queue.ts +++ b/commands/music/queue.ts @@ -4,7 +4,8 @@ module.exports = { description: "Shows the song queue", aliases: ["q"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/remove.ts b/commands/music/remove.ts new file mode 100644 index 0000000..77a3d75 --- /dev/null +++ b/commands/music/remove.ts @@ -0,0 +1,76 @@ +import { Command } from "../../types/command"; +const skip = require("./skip"); + +module.exports = { + aliases: ["rm"], + description: "Removes a song from the queue", + commandOptions: { + connectedToSameVC: true, + guildOnly: true + }, + + async run(client, message, args, guildData, userData, isSlashCommand) { + const playerInfo = client.player.getQueue(message.guild?.id); + + let start, end; + + if (args[0] === "all") { + start = 1; + end = playerInfo.queue.length; + } else if (args[0] === "last") { + start = playerInfo.queue.length; + end = playerInfo.queue.length; + } else { + start = parseInt(args[0]); + end = parseInt(args[1]); + } + + if (isNaN(start)) { + return "Please provide a valid number"; + } else if (isNaN(end)) { + end = start; + } + + if (start < 0 || start > playerInfo.queue.length) { + return "Please provide a valid number"; + } else if (end < 0 || end > playerInfo.queue.length) { + return "Please provide a valid number"; + } + + if (start > end) { + const temp = start; + start = end; + end = temp; + } + + let removedString = ""; + + let removedCurrent = false; + + if (start === 0) { + removedString += `${0}. **${playerInfo.current.title}**\n`; + await skip.run(client, message, [], guildData, userData, isSlashCommand); + start = 1; + removedCurrent = true; + } + + const elementsToRemove = end - start + 1; + + const removedElements = playerInfo.queue.splice(start - 1, elementsToRemove); + + const removedStringElementsMax = removedCurrent ? 18 : 19; + const removeStringUnfinished = removedElements.length > removedStringElementsMax; + + for (let i = 0; i < Math.min(removedElements.length, removedStringElementsMax); i++) { + removedString += `${i + 1}. **${removedElements[i].title}**\n`; + } + + if (removeStringUnfinished) { + removedString += `And ${removedElements.length - removedStringElementsMax} more...`; + } + + const removedElementsNumber = elementsToRemove + (removedCurrent ? 1 : 0); + + return `Removed ${removedElementsNumber} element${removedElementsNumber > 1 ? "s" : ""} from the queue: \n${removedString} `; + } +} as Command; diff --git a/commands/music/resume.ts b/commands/music/resume.ts index 09abc9b..944e771 100644 --- a/commands/music/resume.ts +++ b/commands/music/resume.ts @@ -4,7 +4,8 @@ module.exports = { aliases: ["unpause"], description: "Resumes playing", commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/shuffle.ts b/commands/music/shuffle.ts index ed541ff..24be711 100644 --- a/commands/music/shuffle.ts +++ b/commands/music/shuffle.ts @@ -4,7 +4,8 @@ module.exports = { description: "Shuffles the queue", aliases: ["mix"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/skip.ts b/commands/music/skip.ts index ca916aa..408d3b1 100644 --- a/commands/music/skip.ts +++ b/commands/music/skip.ts @@ -4,7 +4,8 @@ module.exports = { description: "Skips current track", aliases: ["next"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/stop.ts b/commands/music/stop.ts index 5c18f03..e21e3e0 100644 --- a/commands/music/stop.ts +++ b/commands/music/stop.ts @@ -4,7 +4,8 @@ module.exports = { description: "Stops the music and clears the queue", aliases: ["disconnect", "leave"], commandOptions: { - connectedToSameVC: true + connectedToSameVC: true, + guildOnly: true }, async run(client, message, _args, _guildData, _userData, _isSlashCommand) { diff --git a/commands/music/troll.ts b/commands/music/troll.ts index c3c855b..bb5a70d 100644 --- a/commands/music/troll.ts +++ b/commands/music/troll.ts @@ -6,7 +6,10 @@ module.exports = { aliases: ["t"], category: "Music", description: "A wild troll appeared.", - connectedToVC: true, + commandOptions: { + connectedToSameVC: true, + guildOnly: true + }, run(client, message, _args, _guildData, _userData, _isSlashCommand) { if (!(message instanceof CommandInteraction)) message.delete(); diff --git a/events/discord/messageCreate.ts b/events/discord/messageCreate.ts index b83098d..3fca940 100644 --- a/events/discord/messageCreate.ts +++ b/events/discord/messageCreate.ts @@ -1,16 +1,19 @@ -import { Message } from "discord.js"; +import { ChannelType, Message } from "discord.js"; import Client from "../../types/client"; import guildModel from "../../schemas/guild"; module.exports = async (client: Client, message: Message) => { if (message.author.bot) return; // Ignore bots - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const guildData = await getGuildData(message.guild!.id); - if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function + if (message.channel.type !== ChannelType.DM) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const guildData = await getGuildData(message.guild!.id); + + if (global.functions.counter(message, guildData)) return; // Check if the message is in the counter channel, if so, run the counter function - if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels + if (!global.functions.checkChannelID(message, guildData)) return; // Ignore messages not in allowed channels + } const prefix = client.config.prefix; // Get the prefix from the .env file diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index 575324e..190b595 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -1,4 +1,4 @@ -import { PermissionResolvable, Message, ActionRowBuilder } from "discord.js"; +import { PermissionResolvable, Message, ActionRowBuilder, ButtonInteraction } from "discord.js"; import { Command, CommandReturns, CommandReturnWithoutString } from "../types/command"; import Client from "../types/client"; import logTime from "../logTime"; @@ -13,17 +13,23 @@ import sendMessage from "./sendMessage"; module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { if (command === undefined) return; if (interaction === undefined) return; - if (interaction.member === null) return interaction.reply("You need to be in a server to use this command."); + if (interaction.member === null && command.commandOptions?.guildOnly) return interaction.reply("You need to be in a server to use this command."); if (client === undefined) return interaction.reply("The bot is currently restarting. Please try again in a few seconds."); - // @ts-expect-error // It will only use the .message property if it's a component interaction - interaction.author ||= interaction.message.author; + let userId: string; + + if (interaction instanceof Message) { + userId = interaction.author.id; + } else { + // @ts-expect-error // why would it ever be never? + userId = interaction.user.id; + } if (command.ignore) return interaction.reply("This command is currently disabled."); if (command.default_member_permissions && !isInteraction - && !interaction.member.permissions.has(command.default_member_permissions as PermissionResolvable)) { + && !interaction.member?.permissions.has(command.default_member_permissions as PermissionResolvable)) { const permissionString = getPermissionsString(command.default_member_permissions); const moreThanOne = (permissionString.match(/,/g) || []).length; const outputString = `You don't have the permission to use this command. You need the following permission${moreThanOne ? "s" : ""}: ${permissionString}`; @@ -33,16 +39,16 @@ module.exports = async (command: Command, client: Client, interaction: Mes if (command.commandOptions?.connectedToSameVC) command.commandOptions.connectedToVC = true; - if (command.commandOptions?.connectedToVC && !interaction.member.voice?.channel) + if (command.commandOptions?.connectedToVC && !interaction.member?.voice?.channel) return interaction.reply("You need to be in a voice channel to use this command."); - if (command.commandOptions?.connectedToSameVC && client.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction.member.voice?.channel?.id) { + if (command.commandOptions?.connectedToSameVC && client.player?.getQueue(interaction.guildId)?.voiceChannel !== interaction.member?.voice?.channel?.id) { if (client.player.getQueue(interaction.guildId)?.voiceChannel === undefined) return interaction.reply("I am not in a voice channel."); return interaction.reply("You need to be in the same voice channel as me to use this command."); } - const cooldownReturn = checkCooldown(command, interaction, client); + const cooldownReturn = checkCooldown(command, userId, client); if (typeof cooldownReturn === "string") return interaction.reply(cooldownReturn); // makes reply unavailable so two replies can't be sent @@ -61,7 +67,7 @@ module.exports = async (command: Command, client: Client, interaction: Mes guildData = await getGuildData(interaction.guild.id); if (guildData === undefined) guildData = null; - const userData = await getUserData(interaction.author.id); + const userData = await getUserData(userId); const startTime = process.hrtime(); const returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); @@ -90,7 +96,7 @@ module.exports = async (command: Command, client: Client, interaction: Mes if (cooldownArray !== undefined) cooldownArray.forEach(commandObject => { - setCooldown(commandObject, interaction, client); + setCooldown(commandObject, userId, client); }); // makes reply available again @@ -170,7 +176,7 @@ function getPermissionsString(permissionString: string) { return perms.join(", "); } -function setCooldown(commandString: Command | string, interaction: Message, client: Client) { +function setCooldown(commandString: Command | string, userId: string, client: Client) { let command: Command; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); @@ -182,13 +188,13 @@ function setCooldown(commandString: Command | string, interaction: Message, clie if (command.name === undefined) return console.error("Could not set cooldown, command has no name: " + command.name); const cooldown = client.commandCooldowns.get(command.name); if (cooldown === undefined) throw new Error("Could not set cooldown, command not found: " + command.name); - cooldown.set(interaction.author.id, Date.now() + command.commandOptions?.cooldown * 1000); + cooldown.set(userId, Date.now() + command.commandOptions?.cooldown * 1000); setTimeout(() => { - cooldown.delete(interaction.author.id); + cooldown.delete(userId); }, command.commandOptions?.cooldown * 1000); } -function checkCooldown(commandString: Command | string, interaction: Message, client: Client): string | boolean { +function checkCooldown(commandString: Command | string, userId: string, client: Client): string | boolean { let command: Command; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); @@ -199,12 +205,12 @@ function checkCooldown(commandString: Command | string, interaction: Message, cl if (command.name === undefined) throw new Error("Could not check cooldown, command has no name: " + command.name); const cooldown = client.commandCooldowns.get(command.name); if (cooldown === undefined) throw new Error("Could not set cooldown, command not found: " + command.name); - const authorCooldown = cooldown.get(interaction.author.id); + const authorCooldown = cooldown.get(userId); if (authorCooldown === undefined) return false; let timeLeft = authorCooldown - Date.now(); timeLeft /= 1000; if (timeLeft < 0) { - cooldown.delete(interaction.author.id); + cooldown.delete(userId); return false; } const timeString = global.functions.convertTime(timeLeft); diff --git a/index.ts b/index.ts index 1719973..29ec6ba 100644 --- a/index.ts +++ b/index.ts @@ -4,8 +4,9 @@ import { Command } from "./types/command"; import ModifiedClient from "./types/client"; import getFiles from "./functions/getFiles"; +import { Partials } from "discord.js"; -const { Client, Collection, GatewayIntentBits } = require("discord.js"); +const { Client, Collection, IntentsBitField } = require("discord.js"); const { connect, connection, set } = require("mongoose"); const Player = require("./music/player"); const fs = require("fs"); @@ -23,14 +24,17 @@ declare global { console.clear(); +const intents = new IntentsBitField(); +intents.add(IntentsBitField.Flags.Guilds); +intents.add(IntentsBitField.Flags.GuildMembers); +intents.add(IntentsBitField.Flags.GuildMessages); +intents.add(IntentsBitField.Flags.GuildVoiceStates); +intents.add(IntentsBitField.Flags.MessageContent); +intents.add(IntentsBitField.Flags.DirectMessages); + const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildVoiceStates, - GatewayIntentBits.MessageContent - ] + intents: intents, + partials: [Partials.Channel], }) as ModifiedClient; /* add important stuff to client */ diff --git a/music/player.ts b/music/player.ts index e050016..5c10857 100644 --- a/music/player.ts +++ b/music/player.ts @@ -48,27 +48,32 @@ module.exports = class Player { this.#client = client; this.#client.on("voiceStateUpdate", (oldState, newState) => { + let channelId = newState.channelId; + if (channelId === undefined) channelId = oldState.channelId; + const queue = this.getQueue(newState.guild.id); - if (queue === undefined || oldState.channelId === null) { - return; - } + if (queue === undefined) return; - if (oldState.id !== this.#client.user.id) { - if (this.#channelEmpty(oldState.channelId)) { - queue.current.channel.send("Leaving channel because it is empty."); - this.#destroyQueue(newState.guild.id); - } - return; - } - if (newState.channelId === undefined) { - queue.current.channel.send("I have been kicked from the channel."); + if (channelId === null) channelId = queue.voiceChannel; + + channelId = channelId as string; + + if (channelId === null) return; + + if (this.#channelEmpty(channelId)) { + queue.current.channel.send("Leaving channel because it is empty."); this.#destroyQueue(newState.guild.id); } - if (oldState.channelId !== newState.channelId) { - queue.voiceChannel = newState.channelId; - } + // @ts-expect-error // MiMiMiMiMi i don't care + if (newState.guild.voiceAdapterCreator.channel) return queue.current.channel.send("I have been kicked from the channel."); + + if (queue === undefined) return; + + if (oldState.id !== this.#client.user.id) return; + + queue.voiceChannel = channelId; }); } @@ -99,7 +104,19 @@ module.exports = class Player { if (guildInfo === undefined) return; guildInfo.current = track; - const streamReturn = await stream(track.url); + let streamReturn; + try { + streamReturn = await stream(track.url); + } catch (e: any) { + if (e.message.includes("Private")) { + // @ts-expect-error // MiMiMiMiMi i don't care + track.channel.send("This video is private. Skipping."); + } else + // @ts-expect-error // MiMiMiMiMi i don't care + track.channel.send("An error occurred while playing the track. Skipping."); + this.skipTrack(guildId); + return; + } const resource = createAudioResource(streamReturn.stream, { inputType: streamReturn.type }); guildInfo.player.play(resource); @@ -244,17 +261,24 @@ module.exports = class Player { if (queue.voiceChannel !== message.member.voice.channel.id) return "You have to be in the same voice channel as the bot to skip tracks."; + this.skipTrack(message.guild.id, queue); + } + + skipTrack(guildId: string, queue?: any) { + if (queue === undefined) queue = this.#queue.get(guildId); + if (queue === undefined) return "No queue for guild."; + const queueElement = queue.queue.shift(); if (queueElement === undefined && !queue.loop) { if (queue.loop) { - this.play(message.guild.id, queueElement || queue.current); + this.play(guildId, queueElement || queue.current); } else { - this.#destroyQueue(message.guild.id); + this.#destroyQueue(guildId); } return { content: "Skipped last track. Leaving channel!", announce: true }; } else { - this.play(message.guild.id, queueElement || queue.current); + this.play(guildId, queueElement || queue.current); return { content: "Skipped track.", announce: true }; } } @@ -314,7 +338,7 @@ module.exports = class Player { #channelEmpty(channelId: string) { // @ts-expect-error // I gotta make this compatible with DM Channels - return this.#client.channels.cache.get(channelId)?.members.filter((member: GuildMember) => !member.user.bot).size === 0; + return this.#client.channels.cache.get(channelId)?.members.filter((member: GuildMember) => !member.user.bot).size < 1; } troll(message: Message) { From ca4a5bc2e4d00628a16c318f475dfd4013cb8922 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 13:15:54 +0100 Subject: [PATCH 19/28] fixed url, made more clear --- README.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 96b08b4..86180f6 100644 --- a/README.md +++ b/README.md @@ -4,29 +4,11 @@ SUS-Bot is a Bot we made for our Discord Server "Stupid Useless Server" (SUS). I ## How to use -### Self Hosting - -1. Clone the Repository -2. Create the `.env` file and fill it with the following content: - -```env -TOKEN= # Your Discord Bot Token -PREFIX= # The Prefix you want to use. For example: ! -PORT= # Port you want your Website to run on. Example: 80 (http) -MONGODB= # Your mongodb connection string -``` - -3. Open CMD -4. Navigate to the Repository -5. Install the Dependencies with `npm i` -6. Run the Bot with `node .` -7. Enjoy - ### Invite the Bot Disclaimer! The Bot is currently under heavy development so it might not be online all the time. -1. Go to the [Invite Page](https://discord.com/api/oauth2/authorize?client_id=1043594673614225429&permissions=8&scope=bot%20applications.commands) +1. Go to the [Invite Page](https://discord.com/api/oauth2/authorize?client_id=1043594673614225429&permissions=8&scope=bot) 2. Select your Server 3. Grant the Permissions 4. Enjoy @@ -35,6 +17,24 @@ P.S. If you want to invite the Bot to your Server, you need to have the `Manage P.P.S. The prefix for the hosted Version is `!` +### Self Hosting + +1. Clone the Repository +2. Create the `.env` file and fill it with the following content: + + ```env + TOKEN= # Your Discord Bot Token + PREFIX= # The Prefix you want to use. For example: ! + PORT= # Port you want your Website to run on. Example: 80 (http) + MONGODB= # Your mongodb connection string + ``` + +3. Open CMD +4. Navigate to the Repository +5. Install the Dependencies with `npm i` +6. Run the Bot with `node .` +7. Enjoy + ## Commands - [ ] means work in progress! From 498b6caf95b8cf018580fa63bae826624a24c889 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 13:19:52 +0100 Subject: [PATCH 20/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86180f6..f56ebfb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ SUS-Bot is a Bot we made for our Discord Server "Stupid Useless Server" (SUS). I Disclaimer! The Bot is currently under heavy development so it might not be online all the time. -1. Go to the [Invite Page](https://discord.com/api/oauth2/authorize?client_id=1043594673614225429&permissions=8&scope=bot) +1. Go to the [Invite Page](https://discord.com/api/oauth2/authorize?client_id=1043594673614225429&permissions=8&scope=bot%20applications.commands) 2. Select your Server 3. Grant the Permissions 4. Enjoy From 18e2de8105c1635bed6e324a1a1b02585c693589 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:18:37 +0100 Subject: [PATCH 21/28] fixed help command --- events/discord/interactionCreate.ts | 26 ++- index.ts | 1 + selectMenus/general/help.ts | 291 +++++++++++++++++++++++++++- types/command.ts | 1 + 4 files changed, 300 insertions(+), 19 deletions(-) diff --git a/events/discord/interactionCreate.ts b/events/discord/interactionCreate.ts index fa179cd..03a0e87 100644 --- a/events/discord/interactionCreate.ts +++ b/events/discord/interactionCreate.ts @@ -25,26 +25,24 @@ module.exports = async (client: Client, interaction: Interaction) => { // @ts-expect-error // same as above args = interaction.options?._hoistedOptions.map(e => e.value); break; - case "BUTTON": + case "BUTTON": { // @ts-expect-error // same as above - if (interaction.customId.startsWith("command:")) { - // @ts-expect-error // same as above - cmd = client.commands.get("command:" + interaction.customId.slice(8)); - // @ts-expect-error // same as above - args = interaction.customId.slice(8).split(" "); - args.shift(); - } else { - // @ts-expect-error // same as above - cmd = client.commands.get("button:" + interaction.customId.split(" ")[0]); - // @ts-expect-error // same as above - args = interaction.customId.split(" "); - args.shift(); + const commandString = interaction.customId; + let commandName = commandString.split(" ")[0]; + if (!(/^.*:.*/.test(commandName))) { + commandName = "button:" + commandName; } + args = commandString.split(" "); + args.shift(); + console.debug(commandName); + cmd = client.commands.get(commandName); + console.debug(cmd, client.commands); isComponent = true; break; + } case "SELECT_MENU": // @ts-expect-error // same as above - cmd = client.commands.get("selectMenu:" + interaction.customId); + cmd = client.commands.get("selectmenu:" + interaction.customId); // @ts-expect-error // same as above args = interaction.customId.split(" "); // @ts-expect-error // same as above diff --git a/index.ts b/index.ts index 29ec6ba..1d6f6f8 100644 --- a/index.ts +++ b/index.ts @@ -110,6 +110,7 @@ function loadCommands(dirName: string, removeTrailingS = true) { return console.warn(`./${dirName}/${dir} is not a directory.`); fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { const command = require(`./${dirName}/${dir}/${file}`); + dirNameCollection = dirNameCollection.toLocaleLowerCase(); command.category = `${dirNameCollection}:` + dir; command.name ||= file.replace(/(\.ts)$/, ""); command.name = `${dirNameCollection}:` + command.name.toLowerCase(); diff --git a/selectMenus/general/help.ts b/selectMenus/general/help.ts index 39f9d05..9112a3c 100644 --- a/selectMenus/general/help.ts +++ b/selectMenus/general/help.ts @@ -1,8 +1,289 @@ -import { Component } from "../../types/command"; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Collection, EmbedBuilder, StringSelectMenuBuilder } from "discord.js"; +import { StringUtil } from "sussy-util"; +import Client from "../../types/client"; +import { Command, Component } from "../../types/command"; +const convertTime = require("../../functions/convertTime"); + +// TODO: edit the help menu instead of sending a new one every time to keep the chat clean module.exports = { - run(_client, _interaction, args, _guildData, _userData) { - console.info("helpmenu.js", args); - return "This command is currently WIP but I already known that you selected " + args[0] + "! MAGIC!"; + run(client, interaction, args, guildData, userData) { + console.debug("Help command ran"); + const commandName = args[0]; + + const command = isCommand(commandName, client); + const category = isCategory(commandName, client); + + console.debug("Command: " + command, "Category: " + category); + + if (commandName === undefined || commandName.length === 0) { + return helpMenuDefault(client); + } else if (command) { + return helpMenuCommand(client, command); + } else if (category) { + return helpMenuCategory(client, category); + } else { + console.debug("No command found for: `" + commandName + "`"); + return "No command found for: `" + commandName + "`"; + } + } +} as Component; + +function isCommand(commandName: string, client: Client): Command | false { + const cmd = client.commands.get(`command:${commandName}`) || + client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + if (cmd === undefined) return false; + return cmd; +} + +function isCategory(categoryName: string, client: Client): Collection | false { + const commands = client.commands.filter(cmd => cmd.category === "command:" + categoryName); + console.debug(client.commands.get("command:help")?.category); + if (commands.size === 0) return false; + return commands; +} + +function helpMenuDefault(client: Client) { + console.debug("Help menu default ran"); + const menu = new StringSelectMenuBuilder() + .setCustomId("help") + .setPlaceholder("Select a category"); + const component = new ActionRowBuilder(); + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Help panel") + // @ts-expect-error // something wrong here, idfk + .setFooter(client.config.embedFooter(client)); + + embed + .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); + + const commands = client.commands.filter(cmd => cmd.category?.startsWith("command:")); + + const categories: string[] = []; + + commands.forEach((cmd) => { + if (!categories.includes(cmd.category?.replace("command:", "") ?? "")) { + categories.push(cmd.category?.replace("command:", "") ?? ""); + } + }); + + categories.forEach((d) => { + embed.addFields({ + name: StringUtil.capitalize(d), + value: "Type `" + client.config.prefix + "help " + d + "` to see more information", + }); + menu.addOptions({ label: StringUtil.capitalize(d), value: d }); + }); + + component.addComponents([menu]); + + return { embeds: [embed], components: [component] }; +} + +function helpMenuCommand(client: Client, commandName: Command | string) { + let cmd: Command | false; + if (typeof commandName === "string") { + cmd = isCommand(commandName, client); + if (cmd === false) return "No command found for: `" + commandName + "`"; + } else { + cmd = commandName; + } + cmd = cmd as Command; + + if (cmd.name === undefined) return "No command found for: `" + commandName + "`"; + + const backButton = new ButtonBuilder() + .setCustomId("selectMenu:help") + .setLabel("<< Back") + .setStyle(ButtonStyle.Primary); + const component = new ActionRowBuilder() + .addComponents([backButton]); + + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Help panel") + // @ts-expect-error // something wrong here, idfk + .setFooter(client.config.embedFooter(client)); + + embed + .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); + + embed.addFields( + { + name: "Name", + value: cmd.name.replace("command:", ""), + inline: true + }, + { + name: "Description", + value: cmd.description, + inline: true + }, + { + name: "Aliases", + value: cmd.aliases ? cmd.aliases.join(", ") : "None", + inline: true + }, + { + name: "Cooldown", + value: cmd.commandOptions?.cooldown ? convertTime(cmd.commandOptions.cooldown) : "None", + inline: true + }, + { + name: "Category", + value: cmd.category ? cmd.category.replace("command:", "") : "None", + inline: true + }, + { + name: "Guild only", + value: cmd.commandOptions?.guildOnly ? "Yes" : "No", + inline: true + }, + { + name: "Usage", + value: cmd.usage ? cmd.usage : "None", + inline: true + } + ); + + return { embeds: [embed], components: [component] }; +} + +function helpMenuCategory(client: Client, commandName: Collection | string) { + let cmd: Collection | false; + if (typeof commandName === "string") { + cmd = isCategory(commandName, client); + if (cmd === false) return "No category found for: `" + commandName + "`"; + } else { + cmd = commandName; } -} as Component; \ No newline at end of file + cmd = cmd as Collection; + + const backButton = new ButtonBuilder() + .setCustomId("selectMenu:help") + .setLabel("<< Back") + .setStyle(ButtonStyle.Primary); + const component = new ActionRowBuilder() + .addComponents([backButton]); + + const menu = new StringSelectMenuBuilder() + .setCustomId("help") + .setPlaceholder("Select a command"); + + const embed = new EmbedBuilder() + .setTimestamp(new Date()) + .setTitle("Help panel") + // @ts-expect-error // something wrong here, idfk + .setFooter(client.config.embedFooter(client)); + + embed + .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); + + let i = 0; + + cmd.forEach((command) => { + if (command.name === undefined) return; + const name = command.name.replace("command:", ""); + embed.addFields({ + name: name, + value: command.description, + }); + menu.addOptions({ label: name, value: name }); + i++; + }); + + const component2 = new ActionRowBuilder() + .addComponents([menu]); + + return { embeds: [embed], components: [component2, component], menu }; +} + + + +// const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, StringSelectMenuBuilder } = require("discord.js"); + +// const { StringUtil } = require("sussy-util"); +// const fs = require("fs"); + +// module.exports = { +// description: "Displays all commands / more information about one command", +// aliases: ["h"], + +// options: [ +// { +// name: "query", +// description: "name of the command", +// type: "STRING", +// required: false, +// } +// ], + +// run(client, message, args, guildData, userData, isSlashCommand) { +// const menu = new StringSelectMenuBuilder() +// .setCustomId("help") +// .setPlaceholder("Select a category"); +// const component = new ActionRowBuilder(); +// const commandName = args[0]; +// const embed = new EmbedBuilder() +// .setTimestamp(new Date()) +// .setTitle("Help panel") +// .setFooter(client.config.embedFooter(client)); + +// if (commandName === undefined || commandName.length === 0) { +// embed +// .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); + +// fs.readdirSync(`${__dirname}/../`).forEach((d) => { +// embed.addFields({ +// name: StringUtil.capitalize(d), +// value: "Type `" + client.config.prefix + "help " + d + "` to see more information", +// }) +// menu.addOptions({ label: StringUtil.capitalize(d), value: d }); +// });; +// } else { +// const cmd = client.commands.get(`command:${commandName}`) || +// client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + +// if (cmd === undefined) { +// return "No command found for: `" + commandName + "`"; +// } + +// // TODO: Add more information + +// embed.addFields( +// { +// name: "Name", +// value: cmd.name, +// inline: true +// }, +// { +// name: "Description", +// value: cmd.description, +// inline: true +// }, +// { +// name: "Category", +// value: cmd.category, +// inline: true +// }, +// { +// name: cmd.aliases?.length > 1 ? "Aliases" : "Alias", +// value: cmd.aliases?.length > 0 ? cmd.aliases.join(", ") : "None", +// inline: true +// }, +// { +// name: "Cooldown", +// value: cmd.cooldown ? `${cmd.cooldown}seconds` : "None", +// inline: true +// } +// ); +// } +// if (menu.options.length > 0) { +// component.addComponents(menu); +// return { embeds: [embed], components: [component] }; +// } else { +// return { embeds: [embed] }; +// } +// } +// } \ No newline at end of file diff --git a/types/command.ts b/types/command.ts index eea2a2e..ae83eb1 100644 --- a/types/command.ts +++ b/types/command.ts @@ -11,6 +11,7 @@ export interface Command { default_member_permissions?: string; commandOptions?: CommandOptions; category?: string; + usage?: string; run: (client: Client, message: CommandInteraction | Message, args: string[], guildData: GuildData, userData: UserData, isInteraction: boolean) => CommandReturns; } From aa6fc9ec20dd8b1440f5a97d0df465f872f4811c Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:18:54 +0100 Subject: [PATCH 22/28] changed Aliases --- commands/economy/resetLevel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/economy/resetLevel.ts b/commands/economy/resetLevel.ts index 2829a60..fdf86b8 100644 --- a/commands/economy/resetLevel.ts +++ b/commands/economy/resetLevel.ts @@ -5,7 +5,7 @@ const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, Colors, ButtonStyle } = r module.exports = { description: "Clears your level", - aliases: ["cll", "clearlevel", "resetlevel", "rl", "resetlvl", "clearlvl"], + aliases: ["clearXP", "resetXP", "clearLevel", "resetLevel"], run(client, message, _args, _guildData, _userData, _isInteraction) { const embed = new EmbedBuilder() From 2958604683b57192edec66db63486c82ab265b02 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:19:10 +0100 Subject: [PATCH 23/28] removed games --- commands/games/coinflip.ts | 26 ---------------------- commands/games/numberguess.ts | 41 ----------------------------------- 2 files changed, 67 deletions(-) delete mode 100644 commands/games/coinflip.ts delete mode 100644 commands/games/numberguess.ts diff --git a/commands/games/coinflip.ts b/commands/games/coinflip.ts deleted file mode 100644 index 81f6b32..0000000 --- a/commands/games/coinflip.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; - -module.exports = { - aliases: ["flip", "coin"], - description: "flips a coin", - options: [{ - name: "headsTails", - type: ApplicationCommandOptionType.String, - description: "select heads or tails", - required: false, - }], - - run(_client, message, args, _guildData, _userData, _isSlashCommand) { - const coinArray = ["heads", "tails"]; - const numberThrow = Math.floor(Math.random() * 2); - if (!(args[0] === "heads") && !(args[0] === "tails")) { - return coinArray[numberThrow]; - } - message.channel?.send(coinArray[numberThrow]); - if (args[0] === coinArray[numberThrow]) { - return "You are victorious!"; - } - return "You are a loser!"; - } -} as Command; diff --git a/commands/games/numberguess.ts b/commands/games/numberguess.ts deleted file mode 100644 index e1e1376..0000000 --- a/commands/games/numberguess.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Command } from "../../types/command"; -import { ApplicationCommandOptionType } from "discord.js"; - -const { IsSomething } = require("sussy-util"); -module.exports = { - aliases: ["number", "guess"], - description: "guess a number between 1 and the specified number", - options: [ - { - name: "number", - type: ApplicationCommandOptionType.Number, - description: "the specified number", - required: true, - }, - { - name: "guess", - type: ApplicationCommandOptionType.Number, - description: "the guessed number", - required: true, - } - ], - - run(_client, message, args, _guildData, _userData, _isSlashCommand) { - if (args[0] === undefined || args[0] === "" || args[1] === undefined || args[1] === "") { - return "Please specify two numbers"; - } - if (!(IsSomething.isNumber(args[0])) || !(IsSomething.isNumber(args[1]))) { - return "Both parameters need to be numbers"; - } - if (args[1] > args[0]) { - return "First number needs to be larger than the second"; - } - const number = Math.round(Math.random() * +args[0] - 1) + 1; - message.channel?.send("Number was generated! The number is: " + number); - - if (number === +(args[1])) { - return "Your number is correct!"; - } else - return "Your number is false!"; - } -} as Command; \ No newline at end of file From 403cde27361bfba02cfef14996258a57afcfea4e Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Fri, 10 Feb 2023 09:39:04 +0100 Subject: [PATCH 24/28] added redirects --- commands/general/help.ts | 81 ++------------------------------- commands/moderation/prepare.ts | 6 +-- events/discord/messageCreate.ts | 3 +- functions/executeCommand.ts | 25 +++++++--- functions/sendMessage.ts | 4 +- index.ts | 7 +-- logTime.ts | 4 +- selectMenus/general/help.ts | 28 +++++++----- types/client.ts | 4 +- types/command.ts | 19 ++++++-- 10 files changed, 68 insertions(+), 113 deletions(-) diff --git a/commands/general/help.ts b/commands/general/help.ts index fa03d76..db759cf 100644 --- a/commands/general/help.ts +++ b/commands/general/help.ts @@ -1,11 +1,6 @@ -import { Command } from "../../types/command"; +import { CommandRedirect } from "../../types/command"; import { ApplicationCommandOptionType } from "discord.js"; -const { EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } = require("discord.js"); - -const { StringUtil } = require("sussy-util"); -const fs = require("fs"); - module.exports = { description: "Displays all commands / more information about one command", aliases: ["h"], @@ -19,75 +14,5 @@ module.exports = { } ], - run(client, _message, args, _guildData, _userData, _isSlashCommand) { - const menu = new StringSelectMenuBuilder() - .setCustomId("help") - .setPlaceholder("Select a category"); - const component = new ActionRowBuilder(); - const commandName = args[0]; - const embed = new EmbedBuilder() - .setTimestamp(new Date()) - .setTitle("Help panel") - // @ts-expect-error // something wrong here, idfk - .setFooter(client.config.embedFooter(client)); - - if (commandName === undefined || commandName.length === 0) { - embed - .setDescription(`To see more information type **${client.config.prefix}help {command name}**`); - - fs.readdirSync(`${__dirname}/../`).forEach((d: unknown) => { - embed.addFields({ - name: StringUtil.capitalize(d), - value: "Type `" + client.config.prefix + "help " + d + "` to see more information", - }); - menu.addOptions({ label: StringUtil.capitalize(d), value: d }); - }); - } else { - const cmd = client.commands.get(`command:${commandName}`) || - client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); - - if (cmd === undefined) { - return "No command found for: `" + commandName + "`"; - } - - // TODO: Add more information - - embed.addFields( - { - name: "Name", - value: cmd.name, - inline: true - }, - { - name: "Description", - value: cmd.description, - inline: true - }, - { - name: "Category", - value: cmd.category, - inline: true - }, - { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - name: cmd.aliases!.length > 1 ? "Aliases" : "Alias", - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - value: cmd.aliases!.length > 0 ? cmd.aliases?.join(", ") : "None", - inline: true - }, - { - name: "Cooldown", - // @ts-expect-error // I'm checking if it exists, so it should be fine - value: cmd.commandOptions?.defaultReturn?.cooldown ? `${cmd.cooldown}seconds` : "None", - inline: true - } - ); - } - if (menu.options.length > 0) { - component.addComponents(menu); - return { embeds: [embed], components: [component] }; - } else { - return { embeds: [embed] }; - } - } -} as Command; + redirect: "selectMenu:help", +} as CommandRedirect; diff --git a/commands/moderation/prepare.ts b/commands/moderation/prepare.ts index b2624e0..4c19517 100644 --- a/commands/moderation/prepare.ts +++ b/commands/moderation/prepare.ts @@ -1,4 +1,4 @@ -import { Command } from "../../types/command"; +import { ProcessedCommands, Commands } from "../../types/command"; import Client from "../../types/client"; import { CommandInteraction, Message } from "discord.js"; import permissionStrings from "../../enums/permissionStrings"; @@ -9,7 +9,7 @@ const registering = (client: Client, message: CommandInteraction | Message const embed = new EmbedBuilder() .setTitle("Success"); - client.commands.forEach((command: Command) => { + client.commands.forEach((command: ProcessedCommands) => { if (command.name === "prepare") return; // @ts-expect-error // cause name can't be undefined, look at index.ts message.guild?.commands?.create(command).catch((error: Error) => { @@ -31,4 +31,4 @@ module.exports = { const embed = registering(client, message); return { embeds: [embed] }; } -} as Command; +} as Commands; diff --git a/events/discord/messageCreate.ts b/events/discord/messageCreate.ts index 3fca940..a37191f 100644 --- a/events/discord/messageCreate.ts +++ b/events/discord/messageCreate.ts @@ -23,7 +23,8 @@ module.exports = async (client: Client, message: Message) => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const commandString = args.shift()!.toLowerCase(); // Get the command name const command = client.commands.get("command:" + commandString) || // Get the command from the commands collection - client.commands.find(command => command.aliases && command.aliases.includes(commandString)); + // @ts-expect-error // If it not defined, it won't be called + client.commands.find(command => command.aliases && command.aliases?.includes(commandString)); // @ts-expect-error // I am God, I can create whatever I want TS! message.followUp = message.reply; diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index 190b595..3ff67dc 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -1,5 +1,5 @@ import { PermissionResolvable, Message, ActionRowBuilder, ButtonInteraction } from "discord.js"; -import { Command, CommandReturns, CommandReturnWithoutString } from "../types/command"; +import { ProcessedCommands, CommandReturns, CommandReturnWithoutString, ProcessedRunnableCommands, ProcessedCommandRedirect } from "../types/command"; import Client from "../types/client"; import logTime from "../logTime"; @@ -10,12 +10,22 @@ import getUserData from "./getUserData"; import sendMessage from "./sendMessage"; -module.exports = async (command: Command, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { +module.exports = async (command: ProcessedCommands, client: Client, interaction: Message, args: string[], isInteraction: boolean, isComponent = false) => { if (command === undefined) return; if (interaction === undefined) return; if (interaction.member === null && command.commandOptions?.guildOnly) return interaction.reply("You need to be in a server to use this command."); if (client === undefined) return interaction.reply("The bot is currently restarting. Please try again in a few seconds."); + // @ts-expect-error // I am literally checking if it's a redirect + if (command.redirect) { + command = command as ProcessedCommandRedirect; + const redirect = command.redirect.toLowerCase(); + command = client.commands.get(redirect) as ProcessedRunnableCommands; + if (command === undefined) throw new Error(`Redirected command ${redirect} does not exist.`); + } + + command = command as ProcessedRunnableCommands; + let userId: string; if (interaction instanceof Message) { @@ -70,6 +80,7 @@ module.exports = async (command: Command, client: Client, interaction: Mes const userData = await getUserData(userId); const startTime = process.hrtime(); + // @ts-expect-error // I just set it to runnable commands const returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); logTime(command, process.hrtime(startTime)); @@ -176,8 +187,8 @@ function getPermissionsString(permissionString: string) { return perms.join(", "); } -function setCooldown(commandString: Command | string, userId: string, client: Client) { - let command: Command; +function setCooldown(commandString: ProcessedCommands | string, userId: string, client: Client) { + let command: ProcessedCommands; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); if (getCommand === undefined) return console.error("Could not set cooldown, command not found: " + commandString); @@ -194,8 +205,8 @@ function setCooldown(commandString: Command | string, userId: string, client: Cl }, command.commandOptions?.cooldown * 1000); } -function checkCooldown(commandString: Command | string, userId: string, client: Client): string | boolean { - let command: Command; +function checkCooldown(commandString: ProcessedCommands | string, userId: string, client: Client): string | boolean { + let command: ProcessedCommands; if (typeof commandString === "string") { const getCommand = client.commands.get(commandString); if (getCommand === undefined) throw new Error("Could not check cooldown, command not found: " + commandString); @@ -217,7 +228,7 @@ function checkCooldown(commandString: Command | string, userId: string, client: return `You are on cooldown for this command, please wait ${timeString}.`; } -async function formatCommandReturn(returnValue: CommandReturns, command: Command): Promise { +async function formatCommandReturn(returnValue: CommandReturns, command: ProcessedCommands): Promise { // eslint-disable-next-line no-async-promise-executor return await new Promise(async (resolve, reject) => { if (returnValue instanceof Promise) { diff --git a/functions/sendMessage.ts b/functions/sendMessage.ts index 1767bfb..2cca785 100644 --- a/functions/sendMessage.ts +++ b/functions/sendMessage.ts @@ -1,9 +1,9 @@ import { Message, Component, ButtonComponent, BaseSelectMenuComponent } from "discord.js"; import Client from "../types/client"; -import { Command, CommandReturnWithoutString } from "../types/command"; +import { ProcessedCommands, CommandReturnWithoutString } from "../types/command"; import { GuildData, UserData } from "../types/data"; -export default async (messageToSend: CommandReturnWithoutString, command: Command, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: GuildData, userData: UserData, isDM: boolean) => { +export default async (messageToSend: CommandReturnWithoutString, command: ProcessedCommands, client: Client, message: Message, args: string[], isInteraction: boolean, guildData: GuildData, userData: UserData, isDM: boolean) => { let sentMessage: Message; if (messageToSend === null) return; diff --git a/index.ts b/index.ts index 1d6f6f8..def6ed8 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,7 @@ //TODO: Add a command to change the prefix //TODO: Add automated testing //TODO: Add the ability to automatically give members with a certain level a role -import { Command } from "./types/command"; +import { ProcessedCommands } from "./types/command"; import ModifiedClient from "./types/client"; import getFiles from "./functions/getFiles"; import { Partials } from "discord.js"; @@ -61,7 +61,7 @@ global.functions = getFiles("./functions"); ].forEach((name) => loadCommands(name, true)); client.commandCooldowns = new Collection(); -client.commands.forEach((command: Command) => { +client.commands.forEach((command: ProcessedCommands) => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- I just set it a few lines above client.commandCooldowns.set(command.name!, new Collection()); }); @@ -109,11 +109,12 @@ function loadCommands(dirName: string, removeTrailingS = true) { if (!fs.lstatSync(`./${dirName}/` + dir).isDirectory()) return console.warn(`./${dirName}/${dir} is not a directory.`); fs.readdirSync(`./${dirName}/${dir}`).filter((file: string) => file.endsWith(".ts")).forEach((file: string) => { - const command = require(`./${dirName}/${dir}/${file}`); + let command = require(`./${dirName}/${dir}/${file}`); dirNameCollection = dirNameCollection.toLocaleLowerCase(); command.category = `${dirNameCollection}:` + dir; command.name ||= file.replace(/(\.ts)$/, ""); command.name = `${dirNameCollection}:` + command.name.toLowerCase(); + command = command as ProcessedCommands; client.commands.set(command.name, command); }); }); diff --git a/logTime.ts b/logTime.ts index 8173d79..6a9a153 100644 --- a/logTime.ts +++ b/logTime.ts @@ -1,7 +1,7 @@ -import { Command } from "./types/command"; +import { ProcessedCommands } from "./types/command"; import fs from "fs"; -export default (command: Command, tookTime: number[]) => { +export default (command: ProcessedCommands, tookTime: number[]) => { if (!command.name) return; const timeMs = tookTime[0] * 1000 + tookTime[1] / 1000000; try { diff --git a/selectMenus/general/help.ts b/selectMenus/general/help.ts index 9112a3c..d103914 100644 --- a/selectMenus/general/help.ts +++ b/selectMenus/general/help.ts @@ -1,7 +1,7 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Collection, EmbedBuilder, StringSelectMenuBuilder } from "discord.js"; import { StringUtil } from "sussy-util"; import Client from "../../types/client"; -import { Command, Component } from "../../types/command"; +import { ProcessedCommands, Command, Component } from "../../types/command"; const convertTime = require("../../functions/convertTime"); // TODO: edit the help menu instead of sending a new one every time to keep the chat clean @@ -29,14 +29,15 @@ module.exports = { } } as Component; -function isCommand(commandName: string, client: Client): Command | false { +function isCommand(commandName: string, client: Client): ProcessedCommands | false { const cmd = client.commands.get(`command:${commandName}`) || - client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + // @ts-expect-error // it won't trigger if it's undefined + client.commands.find(cmd => cmd.aliases && cmd.aliases?.includes(commandName)); if (cmd === undefined) return false; return cmd; } -function isCategory(categoryName: string, client: Client): Collection | false { +function isCategory(categoryName: string, client: Client): Collection | false { const commands = client.commands.filter(cmd => cmd.category === "command:" + categoryName); console.debug(client.commands.get("command:help")?.category); if (commands.size === 0) return false; @@ -81,15 +82,15 @@ function helpMenuDefault(client: Client) { return { embeds: [embed], components: [component] }; } -function helpMenuCommand(client: Client, commandName: Command | string) { - let cmd: Command | false; +function helpMenuCommand(client: Client, commandName: ProcessedCommands | string) { + let cmd: ProcessedCommands | false; if (typeof commandName === "string") { cmd = isCommand(commandName, client); if (cmd === false) return "No command found for: `" + commandName + "`"; } else { cmd = commandName; } - cmd = cmd as Command; + cmd = cmd as ProcessedCommands; if (cmd.name === undefined) return "No command found for: `" + commandName + "`"; @@ -117,11 +118,13 @@ function helpMenuCommand(client: Client, commandName: Command | string) { }, { name: "Description", - value: cmd.description, + // @ts-expect-error // I am checking if it's undefined + value: cmd.description ? cmd.description : "None", inline: true }, { name: "Aliases", + // @ts-expect-error // I am checking if it's undefined value: cmd.aliases ? cmd.aliases.join(", ") : "None", inline: true }, @@ -150,15 +153,15 @@ function helpMenuCommand(client: Client, commandName: Command | string) { return { embeds: [embed], components: [component] }; } -function helpMenuCategory(client: Client, commandName: Collection | string) { - let cmd: Collection | false; +function helpMenuCategory(client: Client, commandName: Collection | string) { + let cmd: Collection | false; if (typeof commandName === "string") { cmd = isCategory(commandName, client); if (cmd === false) return "No category found for: `" + commandName + "`"; } else { cmd = commandName; } - cmd = cmd as Collection; + cmd = cmd as Collection; const backButton = new ButtonBuilder() .setCustomId("selectMenu:help") @@ -187,7 +190,8 @@ function helpMenuCategory(client: Client, commandName: Collection extends DiscordClient { - commands: Collection; + commands: Collection; player: Player; commandCooldowns: Collection>; config: ClientConfig; diff --git a/types/command.ts b/types/command.ts index ae83eb1..fd183ce 100644 --- a/types/command.ts +++ b/types/command.ts @@ -4,7 +4,6 @@ import { UserData, GuildData } from "./data"; export interface Command { ignore?: boolean; - name?: string; aliases?: string[]; description: string; options?: ApplicationCommandOption[]; @@ -27,7 +26,7 @@ interface CommandOptions { interface extensionWithoutDM { announce?: boolean; success?: boolean; - setCooldown?: Command[]; + setCooldown?: Commands[]; disableOriginal?: boolean; deleteMessage?: boolean | number; deleteReply?: boolean | number; @@ -63,4 +62,18 @@ export type CommandReturns = CommandReturn | AsyncCommandReturn; // type Overwrite = Pick> & U; -export type Component = Omit; \ No newline at end of file +export type Component = Omit; + +export type CommandRedirect = Omit & { redirect: string }; + +export type ProcessedCommand = Command & { name: string }; + +export type ProcessedCommandRedirect = CommandRedirect & { name: string }; + +export type ProcessedComponent = Component & { name: string }; + +export type ProcessedCommands = ProcessedCommand | ProcessedCommandRedirect | ProcessedComponent; + +export type ProcessedRunnableCommands = ProcessedCommand | ProcessedCommandRedirect; + +export type Commands = Command | CommandRedirect | Component; \ No newline at end of file From 6a569423c83a879690d08de266595c3247df8050 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Fri, 10 Feb 2023 09:42:34 +0100 Subject: [PATCH 25/28] removed unnecessary import --- functions/executeCommand.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index 3ff67dc..e92d433 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -1,4 +1,4 @@ -import { PermissionResolvable, Message, ActionRowBuilder, ButtonInteraction } from "discord.js"; +import { PermissionResolvable, Message, ActionRowBuilder } from "discord.js"; import { ProcessedCommands, CommandReturns, CommandReturnWithoutString, ProcessedRunnableCommands, ProcessedCommandRedirect } from "../types/command"; import Client from "../types/client"; import logTime from "../logTime"; @@ -145,7 +145,7 @@ module.exports = async (command: ProcessedCommands, client: Client, intera } }; -// function that converts default_member_permissions bitfield to a human readable string +// function that converts default_member_permissions bitField to a human readable string function getPermissionsString(permissionString: string) { const permissions = parseInt(permissionString); From e98b99495104cb7a8cd97e581dfe9d0bfc2efdd8 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Fri, 10 Feb 2023 09:50:20 +0100 Subject: [PATCH 26/28] added 2 loading logs --- index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/index.ts b/index.ts index def6ed8..1aeb1f3 100644 --- a/index.ts +++ b/index.ts @@ -51,8 +51,12 @@ declare global { var functions: any; } +console.log("Loading functions..."); + global.functions = getFiles("./functions"); +console.log("Loading commands..."); + /* Loading all the commands. */ [ "commands", From 71602b3ad2b0b2b654933339d0804e1be773a5dc Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Fri, 10 Feb 2023 09:50:37 +0100 Subject: [PATCH 27/28] fixed bug and added ComponentRedirect --- functions/executeCommand.ts | 1 - types/command.ts | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/functions/executeCommand.ts b/functions/executeCommand.ts index e92d433..8ad4a00 100644 --- a/functions/executeCommand.ts +++ b/functions/executeCommand.ts @@ -80,7 +80,6 @@ module.exports = async (command: ProcessedCommands, client: Client, intera const userData = await getUserData(userId); const startTime = process.hrtime(); - // @ts-expect-error // I just set it to runnable commands const returnValue: CommandReturnWithoutString = await formatCommandReturn(command.run(client, interaction, args, guildData, userData, isInteraction), command); logTime(command, process.hrtime(startTime)); diff --git a/types/command.ts b/types/command.ts index fd183ce..4d1d915 100644 --- a/types/command.ts +++ b/types/command.ts @@ -70,10 +70,14 @@ export type ProcessedCommand = Command & { name: string }; export type ProcessedCommandRedirect = CommandRedirect & { name: string }; +export type ComponentRedirect = Omit & { redirect: string }; + +export type ProcessedComponentRedirect = ComponentRedirect & { name: string }; + export type ProcessedComponent = Component & { name: string }; -export type ProcessedCommands = ProcessedCommand | ProcessedCommandRedirect | ProcessedComponent; +export type ProcessedCommands = ProcessedCommand | ProcessedCommandRedirect | ProcessedComponent | ProcessedComponentRedirect; -export type ProcessedRunnableCommands = ProcessedCommand | ProcessedCommandRedirect; +export type ProcessedRunnableCommands = ProcessedCommand; -export type Commands = Command | CommandRedirect | Component; \ No newline at end of file +export type Commands = Command | CommandRedirect | Component | ComponentRedirect; \ No newline at end of file From 330af104ee7795e8ed9a0267395092dbf1ceee62 Mon Sep 17 00:00:00 2001 From: plastik-flasche <102389009+plastik-flasche@users.noreply.github.com> Date: Fri, 10 Feb 2023 11:18:44 +0100 Subject: [PATCH 28/28] fixed issues --- Issues.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Issues.md b/Issues.md index d96d48c..56e9273 100644 --- a/Issues.md +++ b/Issues.md @@ -2,7 +2,7 @@ - [x] When outputting time, format seconds to seconds, minutes, hours, days, ... - [x] When resetting balance/level the YES/NO message can be seen by everyone which would reset the balance of everyone clicking on the button -- [ ] Fix help command +- [x] Fix help command - [x] Fix coinflip: returned nothing - [x] Fix !numberguess: Number was generated! The number is: NaN @@ -10,10 +10,10 @@ __returned nothing__ - [x] Fix queue: if queue is too long it could exceed the 2000 character limit imposed by discord - [x] deferReply() will crash the bot -- [ ] beg is currently broken +- [x] beg is currently broken - [ ] fix bet messages, kinda ugly and overcrowded imo - [x] search returns nothing -- [ ] rewrite search so it used buttons instead of having to listen for messages sent by the user +- [x] rewrite search so it used buttons instead of having to listen for messages sent by the user - [x] withdraw returns nothing - [ ] can't check balance of other users - [ ] make a leaderboard command @@ -56,5 +56,5 @@ message_reference: Unknown message - [x] search gives you a cooldown even when you didn't search anything - [ ] job doesn't display which level is required to get the job - [ ] coinflip "You are victorious!"... Like WTF?! Mb think 5 secs before writing that -- [ ] when adding videos via an url, the bot doesn't check if the url is valid, so the queue element could be undefined, when trying to skip and it's undefined the bot prints an error to the console and doesn't skip the song, when asked to skip again it skips to the song after the undefined one -- [ ] when joining from another channel, the bot says "Leaving channel because it is empty" and leaves the channel +- [x] when adding videos via an url, the bot doesn't check if the url is valid, so the queue element could be undefined, when trying to skip and it's undefined the bot prints an error to the console and doesn't skip the song, when asked to skip again it skips to the song after the undefined one +- [x] when joining from another channel, the bot says "Leaving channel because it is empty" and leaves the channel