324 lines
11 KiB
JavaScript
324 lines
11 KiB
JavaScript
const config = require("./config.json");
|
|
const Discord = require("discord.js");
|
|
const {
|
|
REST,
|
|
Routes
|
|
} = require('discord.js');
|
|
const rest = new REST({
|
|
version: '10'
|
|
}).setToken(config.discord.token);
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const colors = require("colors");
|
|
|
|
const sqlite3 = require("sqlite3").verbose();
|
|
const db = new sqlite3.Database("./database.db");
|
|
|
|
// If database table doesnt exist, create it
|
|
// two tables, one for per-guild settings, one for keeping track of temp voice channels
|
|
// guild_settings: guild_id text, voice_category_id text, creation_channel_id text, max_temp_channels integer, max_per_user integer
|
|
// temp_channels: channel_id text, guild_id text, creator_id text
|
|
|
|
db.run(`CREATE TABLE IF NOT EXISTS guild_settings (
|
|
voice_category_id TEXT PRIMARY KEY,
|
|
guild_id TEXT,
|
|
creation_channel_id TEXT
|
|
)`);
|
|
|
|
db.run(`CREATE TABLE IF NOT EXISTS temp_channels (
|
|
channel_id TEXT PRIMARY KEY,
|
|
guild_id TEXT,
|
|
creator_id TEXT
|
|
)`);
|
|
|
|
const client = new Discord.Client({
|
|
intents: [
|
|
"Guilds",
|
|
"GuildVoiceStates"
|
|
]
|
|
});
|
|
|
|
client.on("ready", async () => {
|
|
console.log(`${colors.cyan("[INFO]")} Logged in as ${colors.green(client.user.tag)}`);
|
|
const commands = [
|
|
{
|
|
name: "setup",
|
|
description: "Setup the bot for your server",
|
|
default_member_permissions: 16,
|
|
options: [
|
|
{
|
|
name: "category",
|
|
description: "The category to create the temporary voice channels in",
|
|
type: 7,
|
|
required: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
console.log(`${colors.cyan("[INFO]")} Started refreshing application (/) commands.`);
|
|
await rest.put(
|
|
Routes.applicationCommands(client.user.id), {
|
|
body: commands
|
|
}
|
|
);
|
|
console.log(`${colors.cyan("[INFO]")} Successfully reloaded application (/) commands.`);
|
|
console.log(`${colors.cyan("[INFO]")} Checking for empty temporary voice channels and missing creation channels.`);
|
|
deletedCreation = 0
|
|
// Run through every category that is set up in the database and make sure the creation channel exists, if not, remove the entry from the database. Dont attempt to make a new channel, its likely they wanted to delete it
|
|
await db.all("SELECT * FROM guild_settings", (err, rows) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
rows.forEach((row) => {
|
|
const guild = client.guilds.cache.get(row.guild_id);
|
|
const voice_category = guild.channels.cache.get(row.voice_category_id);
|
|
const creation_channel = guild.channels.cache.get(row.creation_channel_id);
|
|
if (!creation_channel) {
|
|
deletedCreation++
|
|
db.run("DELETE FROM guild_settings WHERE voice_category_id = ?", row.voice_category_id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
deletedTemp = 0;
|
|
// Run through every temp channel in the database, if it's empty delete it
|
|
await db.all("SELECT * FROM temp_channels", (err, rows) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
rows.forEach((row) => {
|
|
const guild = client.guilds.cache.get(row.guild_id);
|
|
const channel = guild.channels.cache.get(row.channel_id);
|
|
if (!channel.members || channel.members.size === 0) {
|
|
deletedTemp+
|
|
channel.delete();
|
|
db.run("DELETE FROM temp_channels WHERE channel_id = ?", row.channel_id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
console.log(`${colors.cyan("[INFO]")} Checked for empty temporary voice channels and missing creation channels. Deleted ${deletedCreation} creation channels and ${deletedTemp} temporary voice channels.`);
|
|
|
|
})
|
|
|
|
client.on("interactionCreate", async (interaction) => {
|
|
if (!interaction.isCommand()) return;
|
|
const command = interaction.commandName;
|
|
switch (command) {
|
|
case "setup": // Initial and post-setup configuration
|
|
// Check if the channel is already set up, if so and no settings are provided, tell the user to specify settings to update, use channel id, not guild.
|
|
// If the channel is not set up, set it up with the provided settings or default settings
|
|
const guild_id = interaction.guild.id;
|
|
const voice_category_id = interaction.options.getChannel("category");
|
|
// Check that voice_category_id is a category
|
|
if (voice_category_id.type !== Discord.ChannelType.GuildCategory) {
|
|
return interaction.reply({
|
|
content: "The channel you selected is not a category! Please select a category to set up the temporary voice channels in.",
|
|
ephemeral: true
|
|
})
|
|
}
|
|
db.get("SELECT * FROM guild_settings WHERE voice_category_id = ?", voice_category_id.id, (err, row) => {
|
|
if (err) {
|
|
console.error(err);
|
|
interaction.reply({
|
|
content: "An error occurred while setting up the channel. Please try again later.",
|
|
ephemeral: true
|
|
});
|
|
}
|
|
if (row) { // Channel already set up, update settings
|
|
// get channel info
|
|
const voice_category = interaction.guild.channels.cache.get(row.voice_category_id);
|
|
// Do a quick check to see if the creation channel still exists, if not, create and update the field for it
|
|
if (!interaction.guild.channels.cache.get(row.creation_channel_id)) {
|
|
interaction.guild.channels.create({
|
|
name: "Create a Channel",
|
|
type: Discord.ChannelType.GuildVoice,
|
|
parent: voice_category_id.id
|
|
}).then((channel) => {
|
|
db.run("UPDATE guild_settings SET creation_channel_id = ? WHERE voice_category_id = ?", channel.id, voice_category_id.id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
interaction.reply({
|
|
content: "An error occurred while updating the channel settings. Please try again later.",
|
|
ephemeral: true
|
|
});
|
|
}
|
|
return interaction.reply({
|
|
content: "Successfully updated the temporary voice channels.",
|
|
ephemeral: true
|
|
});
|
|
});
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
interaction.reply({
|
|
content: "An error occurred while updating the channel settings. Please try again later.",
|
|
ephemeral: true
|
|
});
|
|
});
|
|
}
|
|
|
|
return interaction.reply({
|
|
content: `The temporary voice channels are already set up in ${voice_category.name}.`,
|
|
ephemeral: true
|
|
});
|
|
} else {
|
|
// Channel not set up, set up channel (make a voice channel in the category called "Create a Channel", then set up the settings)
|
|
|
|
// Create the channel
|
|
interaction.guild.channels.create({
|
|
name: "Create a Channel",
|
|
type: Discord.ChannelType.GuildVoice,
|
|
parent: voice_category_id.id
|
|
}).then((channel) => {
|
|
// Set up the settings
|
|
db.run("INSERT INTO guild_settings (voice_category_id, guild_id, creation_channel_id) VALUES (?, ?, ?)", voice_category_id.id, guild_id, channel.id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
interaction.reply({
|
|
content: "An error occurred while setting up the channel. Please try again later.",
|
|
ephemeral: true
|
|
});
|
|
}
|
|
interaction.reply({
|
|
content: `Successfully set up the temporary voice channels in ${voice_category_id.name}.`,
|
|
ephemeral: true
|
|
});
|
|
});
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
interaction.reply({
|
|
content: "An error occurred while setting up the channel. Please try again later.",
|
|
ephemeral: true
|
|
});
|
|
});
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
}
|
|
});
|
|
|
|
client.on("voiceStateUpdate", async (oldState, newState) => {
|
|
// Handle creation
|
|
// Check if the user is in a creation channel, if so make a new channel, name format is temp #<tempchannel count for guild>, then move them there
|
|
if (newState.channel) {
|
|
db.get("SELECT * FROM guild_settings WHERE creation_channel_id = ?", newState.channel.id, (err, row) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
if (row) {
|
|
// User is in a creation channel
|
|
const guild = newState.guild.id;
|
|
const creator = newState.member.id;
|
|
// Get the number of temp channels in a guild
|
|
db.get("SELECT COUNT(*) FROM temp_channels WHERE guild_id = ?", guild, (err, row2) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
const temp_channel_count = row2["COUNT(*)"];
|
|
// Create a new channel
|
|
newState.guild.channels.create({
|
|
name: `Temp #${temp_channel_count + 1}`,
|
|
type: Discord.ChannelType.GuildVoice,
|
|
parent: row.voice_category_id
|
|
}).then((channel) => {
|
|
channel.send({
|
|
embeds: [
|
|
{
|
|
color: 0xff0000,
|
|
title: "Temporary Voice Channel",
|
|
description: `This is a temporary voice channel created by ${newState.member.user}.\nThis voice channel and the messages within will be deleted when the channel is empty!`,
|
|
}
|
|
]
|
|
});
|
|
// Move the user to the new channel
|
|
newState.setChannel(channel);
|
|
// Update the database
|
|
db.run("INSERT INTO temp_channels (channel_id, guild_id, creator_id) VALUES (?, ?, ?)", channel.id, guild, creator, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}).catch((err) => {
|
|
console.error(err);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
// Handle deletion
|
|
// Check if the user left a temp channel, if they were the last person in the channel, delete it
|
|
if (oldState.channel) {
|
|
db.get("SELECT * FROM temp_channels WHERE channel_id = ?", oldState.channel.id, (err, row) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
if (row) {
|
|
// User left a temp channel
|
|
const channel = oldState.channel;
|
|
// Check if the user was the last person in the channel
|
|
if (!channel.members || channel.members.size === 0) {
|
|
// Delete the channel
|
|
channel.delete();
|
|
// Update the database
|
|
db.run("DELETE FROM temp_channels WHERE channel_id = ?", channel.id , (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
client.on("channelDelete", async (channel) => {
|
|
// Check if the channel deleted was a creation channel, if so, remove the settings from the database
|
|
db.get("SELECT * FROM guild_settings WHERE creation_channel_id = ?", channel.id, (err, row) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
if (row) {
|
|
db.run("DELETE FROM guild_settings WHERE creation_channel_id = ?", channel.id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Check if it was a temp channel, if so, delete it from the database
|
|
db.get("SELECT * FROM temp_channels WHERE channel_id = ?", channel.id, (err, row) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
if (row) {
|
|
db.run("DELETE FROM temp_channels WHERE channel_id = ?", channel.id, (err) => {
|
|
if (err) {
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Lets actually handle exceptions now
|
|
process.on('unhandledRejection', (error) => {
|
|
// Log a full error with line number
|
|
console.log(`${colors.red("[ERROR]")} ${error}`);
|
|
});
|
|
|
|
process.on('uncaughtException', (error) => {
|
|
// Log a full error with line number
|
|
console.log(`${colors.red("[ERROR]")} ${error}`);
|
|
});
|
|
|
|
client.login(config.discord.token) |