diff options
| author | Max Isom <[email protected]> | 2020-03-09 11:57:39 -0500 |
|---|---|---|
| committer | Max Isom <[email protected]> | 2020-03-09 11:57:39 -0500 |
| commit | eca84c8b6964af29948510a02ebfeb5f23244921 (patch) | |
| tree | ffa8a25a19ea9e57b33db661c28a80104a0087e7 /src | |
| parent | afadcb9ee5482c0a1c52b3d55e948e2a8a9ac0cb (diff) | |
| download | muse-eca84c8b6964af29948510a02ebfeb5f23244921.tar.xz muse-eca84c8b6964af29948510a02ebfeb5f23244921.zip | |
Inital commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/commands/config.ts | 24 | ||||
| -rw-r--r-- | src/events/guild-create.ts | 73 | ||||
| -rw-r--r-- | src/index.ts | 58 | ||||
| -rw-r--r-- | src/interfaces.ts | 7 | ||||
| -rw-r--r-- | src/models/index.ts | 5 | ||||
| -rw-r--r-- | src/models/settings.ts | 18 | ||||
| -rw-r--r-- | src/packages.d.ts | 1 | ||||
| -rw-r--r-- | src/utils/config.ts | 7 | ||||
| -rw-r--r-- | src/utils/db.ts | 11 |
9 files changed, 204 insertions, 0 deletions
diff --git a/src/commands/config.ts b/src/commands/config.ts new file mode 100644 index 0000000..fb79059 --- /dev/null +++ b/src/commands/config.ts @@ -0,0 +1,24 @@ +import {CommandHandler} from '../interfaces'; + +const config: CommandHandler = { + name: 'config', + description: 'Change various bot settings.', + execute: (msg, args) => { + const setting = args[0]; + + switch (setting) { + case 'prefix': + msg.channel.send('Prefix set'); + break; + + case 'channel': + msg.channel.send('Channel bound'); + break; + + default: + msg.channel.send('Unknown setting'); + } + } +}; + +export default config; diff --git a/src/events/guild-create.ts b/src/events/guild-create.ts new file mode 100644 index 0000000..3675b2c --- /dev/null +++ b/src/events/guild-create.ts @@ -0,0 +1,73 @@ +import {Guild, MessageReaction, TextChannel} from 'discord.js'; +import emoji from 'node-emoji'; +import {Settings} from '../models'; + +const DEFAULT_PREFIX = '!'; + +export default async (guild: Guild): Promise<void> => { + await Settings.upsert({guildId: guild.id, prefix: DEFAULT_PREFIX}); + + const owner = await guild.client.users.fetch(guild.ownerID); + + let firstStep = '👋 Hi!\n'; + firstStep += 'I just need to ask a few questions before you start listening to music.\n\n'; + firstStep += 'First, what channel should I listen to for music commands?\n\n'; + + interface EmojiChannel { + name: string; + id: string; + emoji: string; + } + + const emojiChannels: EmojiChannel[] = []; + + for (const [channelId, channel] of guild.channels.cache) { + if (channel.type === 'text') { + emojiChannels.push({ + name: channel.name, + id: channelId, + emoji: emoji.random().emoji + }); + } + } + + for (const channel of emojiChannels) { + firstStep += `${channel.emoji}: #${channel.name}\n`; + } + + firstStep += '\n'; + + // Send message + const msg = await owner.send(firstStep); + + // Add reactions + for await (const channel of emojiChannels) { + await msg.react(channel.emoji); + } + + const reactions = await msg.awaitReactions((reaction, user) => user.id !== msg.author.id && emojiChannels.map(e => e.emoji).includes(reaction.emoji.name), {max: 1}); + + const choice = reactions.first() as MessageReaction; + + const chosenChannel = emojiChannels.find(e => e.emoji === choice.emoji.name) as EmojiChannel; + + // Second setup step (get prefix) + let secondStep = `👍 Cool, I'll listen to **#${chosenChannel.name}** \n\n`; + secondStep += 'Last question: what character should I use for a prefix? Type a single character and hit enter.'; + + await owner.send(secondStep); + + const prefixResponses = await msg.channel.awaitMessages(r => r.content.length === 1, {max: 1}); + + const prefixCharacter = prefixResponses.first()!.content; + + // Save settings + await Settings.update({prefix: prefixCharacter, channel: chosenChannel.id}, {where: {guildId: guild.id}}); + + // Send welcome + const boundChannel = guild.client.channels.cache.get(chosenChannel.id) as TextChannel; + + await boundChannel.send(`hey <@${owner.id}> try \`${prefixCharacter}play https://www.youtube.com/watch?v=dQw4w9WgXcQ\``); + + await msg.channel.send(`Sounds good. Check out **#${chosenChannel.name}** to get started.`); +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..5771988 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,58 @@ +import fs from 'fs'; +import path from 'path'; +import makeDir from 'make-dir'; +import Discord from 'discord.js'; +import {DISCORD_TOKEN, DISCORD_CLIENT_ID, DATA_DIR} from './utils/config'; +import {sequelize} from './utils/db'; +import {CommandHandler} from './interfaces'; +import handleGuildCreate from './events/guild-create'; + +const PREFIX = '!'; + +const client = new Discord.Client(); +const commands = new Discord.Collection(); + +// Load in commands +const commandFiles = fs.readdirSync(path.join(__dirname, 'commands')).filter(file => file.endsWith('.js')); + +for (const file of commandFiles) { + const command = require(`./commands/${file}`).default; + + commands.set(command.name, command); +} + +// Generic message handler +client.on('message', (msg: Discord.Message) => { + if (!msg.content.startsWith(PREFIX) || msg.author.bot) { + return; + } + + const args = msg.content.slice(PREFIX.length).split(/ +/); + const command = args.shift()!.toLowerCase(); + + if (!commands.has(command)) { + return; + } + + try { + const handler = commands.get(command) as CommandHandler; + + handler.execute(msg, args); + } catch (error) { + console.error(error); + msg.reply('there was an error trying to execute that command!'); + } +}); + +client.on('ready', async () => { + // Create directory if necessary + await makeDir(DATA_DIR); + + await sequelize.sync({}); + + console.log(`Ready! Invite the bot with https://discordapp.com/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&scope=bot`); +}); + +client.on('guildCreate', handleGuildCreate); + +client.login(DISCORD_TOKEN); diff --git a/src/interfaces.ts b/src/interfaces.ts new file mode 100644 index 0000000..b002a65 --- /dev/null +++ b/src/interfaces.ts @@ -0,0 +1,7 @@ +import Discord from 'discord.js'; + +export interface CommandHandler { + name: string; + description: string; + execute: (msg: Discord.Message, args: string[]) => void; +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..6898b0e --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,5 @@ +import Settings from './settings'; + +export { + Settings +}; diff --git a/src/models/settings.ts b/src/models/settings.ts new file mode 100644 index 0000000..29c2b3e --- /dev/null +++ b/src/models/settings.ts @@ -0,0 +1,18 @@ +import {Table, Column, PrimaryKey, Model, Default} from 'sequelize-typescript'; + +@Table +export default class Settings extends Model<Settings> { + @PrimaryKey + @Column + guildId!: string; + + @Column + prefix!: string; + + @Column + channel!: string; + + @Default(false) + @Column + finishedSetup!: boolean; +} diff --git a/src/packages.d.ts b/src/packages.d.ts new file mode 100644 index 0000000..029763f --- /dev/null +++ b/src/packages.d.ts @@ -0,0 +1 @@ +declare module 'node-emoji'; diff --git a/src/utils/config.ts b/src/utils/config.ts new file mode 100644 index 0000000..db70d7f --- /dev/null +++ b/src/utils/config.ts @@ -0,0 +1,7 @@ +import dotenv from 'dotenv'; +import path from 'path'; +dotenv.config(); + +export const DISCORD_TOKEN: string = process.env.DISCORD_TOKEN ? process.env.DISCORD_TOKEN : ''; +export const DISCORD_CLIENT_ID: string = process.env.DISCORD_CLIENT_ID ? process.env.DISCORD_CLIENT_ID : ''; +export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data'); diff --git a/src/utils/db.ts b/src/utils/db.ts new file mode 100644 index 0000000..6010df4 --- /dev/null +++ b/src/utils/db.ts @@ -0,0 +1,11 @@ +import {Sequelize} from 'sequelize-typescript'; +import path from 'path'; +import {DATA_DIR} from '../utils/config'; +import {Settings} from '../models'; + +export const sequelize = new Sequelize({ + dialect: 'sqlite', + database: 'muse', + storage: path.join(DATA_DIR, 'db.sqlite'), + models: [Settings] +}); |
