aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Isom <[email protected]>2020-03-09 11:57:39 -0500
committerMax Isom <[email protected]>2020-03-09 11:57:39 -0500
commiteca84c8b6964af29948510a02ebfeb5f23244921 (patch)
treeffa8a25a19ea9e57b33db661c28a80104a0087e7 /src
parentafadcb9ee5482c0a1c52b3d55e948e2a8a9ac0cb (diff)
downloadmuse-eca84c8b6964af29948510a02ebfeb5f23244921.tar.xz
muse-eca84c8b6964af29948510a02ebfeb5f23244921.zip
Inital commit
Diffstat (limited to 'src')
-rw-r--r--src/commands/config.ts24
-rw-r--r--src/events/guild-create.ts73
-rw-r--r--src/index.ts58
-rw-r--r--src/interfaces.ts7
-rw-r--r--src/models/index.ts5
-rw-r--r--src/models/settings.ts18
-rw-r--r--src/packages.d.ts1
-rw-r--r--src/utils/config.ts7
-rw-r--r--src/utils/db.ts11
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]
+});