mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-27 13:11:03 +00:00
feat(bots/discord): framework changes and new features
- Migrated to a new command framework which looks better and works better - Fixed commands not being bundled correctly - Added message (prefix) commands with argument validation - Added a new CommandErrorType, for invalid arguments - `/eval` is now a bit safer - Corrected colors for the coinflip embed - `/stop` now works even when the bot is not connected to the API
This commit is contained in:
34
bots/discord/src/commands/admin/eval.ts
Normal file
34
bots/discord/src/commands/admin/eval.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { inspect } from 'util'
|
||||
import { runInNewContext } from 'vm'
|
||||
import { ApplicationCommandOptionType } from 'discord.js'
|
||||
|
||||
import { AdminCommand } from '$/classes/Command'
|
||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||
|
||||
export default new AdminCommand({
|
||||
name: 'eval',
|
||||
description: 'Make the bot less sentient by evaluating code',
|
||||
options: {
|
||||
code: {
|
||||
description: 'The code to evaluate',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
['show-hidden']: {
|
||||
description: 'Show hidden properties',
|
||||
type: ApplicationCommandOptionType.Boolean,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
async execute(context, trigger, { code, 'show-hidden': showHidden }) {
|
||||
await trigger.reply({
|
||||
ephemeral: true,
|
||||
embeds: [
|
||||
createSuccessEmbed('Evaluate', `\`\`\`js\n${code}\`\`\``).addFields({
|
||||
name: 'Result',
|
||||
value: `\`\`\`js\n${inspect(runInNewContext(code, { client: trigger.client, context, trigger }), { depth: 1, showHidden, getters: true, numericSeparator: true, showProxy: true })}\`\`\``,
|
||||
}),
|
||||
],
|
||||
})
|
||||
},
|
||||
})
|
||||
21
bots/discord/src/commands/admin/exception-test.ts
Normal file
21
bots/discord/src/commands/admin/exception-test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ApplicationCommandOptionType } from 'discord.js'
|
||||
|
||||
import { AdminCommand } from '$/classes/Command'
|
||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||
|
||||
export default new AdminCommand({
|
||||
name: 'exception-test',
|
||||
description: 'Makes the bot intentionally hate you by throwing an exception',
|
||||
options: {
|
||||
type: {
|
||||
description: 'The type of exception to throw',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
choices: Object.keys(CommandErrorType).map(k => ({ name: k, value: k })),
|
||||
},
|
||||
},
|
||||
async execute(_, __, { type }) {
|
||||
if (type === 'Process') throw new Error('Intentional process exception')
|
||||
throw new CommandError(CommandErrorType[type as keyof typeof CommandErrorType], 'Intentional bot design') // ;)
|
||||
},
|
||||
})
|
||||
93
bots/discord/src/commands/admin/slash-commands.ts
Normal file
93
bots/discord/src/commands/admin/slash-commands.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { ApplicationCommandOptionType, Routes } from 'discord.js'
|
||||
|
||||
import { AdminCommand } from '$/classes/Command'
|
||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||
|
||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||
|
||||
const SubcommandOptions = {
|
||||
where: {
|
||||
description: 'Where to register the commands',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
choices: [
|
||||
{ name: 'globally', value: 'global' },
|
||||
{ name: 'this server', value: 'server' },
|
||||
],
|
||||
required: true,
|
||||
},
|
||||
} as const
|
||||
|
||||
export default new AdminCommand({
|
||||
name: 'slash-commands',
|
||||
description: 'Register or delete slash commands',
|
||||
options: {
|
||||
register: {
|
||||
description: 'Register slash commands',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: SubcommandOptions,
|
||||
},
|
||||
delete: {
|
||||
description: 'Delete slash commands',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: SubcommandOptions,
|
||||
},
|
||||
},
|
||||
allowMessageCommand: true,
|
||||
async execute(context, trigger, { delete: deleteOption, register }) {
|
||||
const action = register ? 'register' : 'delete'
|
||||
const { where } = (deleteOption ?? register)!
|
||||
|
||||
if (!trigger.inGuild())
|
||||
throw new CommandError(CommandErrorType.Generic, 'This command can only be used in a server.')
|
||||
|
||||
const { global: globalCommands, guild: guildCommands } = Object.groupBy(
|
||||
Object.values(context.discord.commands),
|
||||
cmd => (cmd.global ? 'global' : 'guild'),
|
||||
)
|
||||
|
||||
const {
|
||||
client,
|
||||
client: { rest },
|
||||
} = trigger
|
||||
|
||||
let response: string | undefined
|
||||
|
||||
switch (action) {
|
||||
case 'register':
|
||||
if (where === 'global') {
|
||||
response = 'Registered global slash commands'
|
||||
|
||||
await rest.put(Routes.applicationCommands(client.application.id), {
|
||||
body: globalCommands?.map(c => c.json),
|
||||
})
|
||||
} else {
|
||||
response = 'Registered slash commands on this server'
|
||||
|
||||
await rest.put(Routes.applicationGuildCommands(client.application.id, trigger.guildId), {
|
||||
body: guildCommands?.map(c => c.json),
|
||||
})
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case 'delete':
|
||||
if (where === 'global') {
|
||||
response = 'Deleted global slash commands'
|
||||
|
||||
await rest.put(Routes.applicationCommands(client.application.id), {
|
||||
body: [],
|
||||
})
|
||||
} else {
|
||||
response = 'Deleted slash commands on this server'
|
||||
|
||||
await rest.put(Routes.applicationGuildCommands(client.application.id, trigger.guildId), {
|
||||
body: [],
|
||||
})
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
await trigger.reply({ embeds: [createSuccessEmbed(response!)] })
|
||||
},
|
||||
})
|
||||
24
bots/discord/src/commands/admin/stop.ts
Normal file
24
bots/discord/src/commands/admin/stop.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { AdminCommand } from '$/classes/Command'
|
||||
|
||||
export default new AdminCommand({
|
||||
name: 'stop',
|
||||
description: "You don't want to run this unless the bot starts to go insane, and like, you really need to stop it.",
|
||||
async execute({ api, logger, executor }, trigger) {
|
||||
api.intentionallyDisconnecting = true
|
||||
|
||||
logger.fatal('Stopping bot...')
|
||||
trigger.reply({
|
||||
content: 'Stopping... (I will go offline once done)',
|
||||
ephemeral: true,
|
||||
})
|
||||
|
||||
if (!api.client.disconnected) api.client.disconnect()
|
||||
logger.warn('Disconnected from API')
|
||||
|
||||
trigger.client.destroy()
|
||||
logger.warn('Disconnected from Discord API')
|
||||
|
||||
logger.info(`Bot stopped, requested by ${executor.id}`)
|
||||
process.exit(0)
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user