aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2022-12-01 21:56:03 -0500
committerAndrew Lee <alee14498@protonmail.com>2022-12-01 21:56:03 -0500
commit894dd858c380e5ac8bcd882294f044c325ef379e (patch)
treeb275ce664f6cf48272d62835bd3010c0e71bc592
parent56573af6e6f5a839536483ea51ad1fc163f33458 (diff)
downloadDLAP-894dd858c380e5ac8bcd882294f044c325ef379e.tar.gz
DLAP-894dd858c380e5ac8bcd882294f044c325ef379e.tar.bz2
DLAP-894dd858c380e5ac8bcd882294f044c325ef379e.zip
Modularized audio backend
-rw-r--r--AudioBackend.js251
-rw-r--r--README.md6
-rw-r--r--backend/AudioControl.js82
-rw-r--r--backend/PlayAudio.js128
-rw-r--r--backend/QueueSystem.js50
-rw-r--r--backend/Shutdown.js60
-rw-r--r--backend/VoiceInitialization.js57
-rw-r--r--bot.js5
-rw-r--r--commands/about.js2
-rw-r--r--commands/join.js2
-rw-r--r--commands/leave.js2
-rw-r--r--commands/next.js3
-rw-r--r--commands/pause.js5
-rw-r--r--commands/play.js7
-rw-r--r--commands/previous.js2
-rw-r--r--commands/reshuffle.js5
-rw-r--r--commands/shutdown.js2
-rw-r--r--commands/status.js5
18 files changed, 402 insertions, 272 deletions
diff --git a/AudioBackend.js b/AudioBackend.js
deleted file mode 100644
index ac26115..0000000
--- a/AudioBackend.js
+++ /dev/null
@@ -1,251 +0,0 @@
-/**************************************************************************
- *
- * DLAP Bot: A Discord bot that plays local audio tracks.
- * (C) Copyright 2022
- * Programmed by Andrew Lee
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- ***************************************************************************/
-
-import {
- createAudioPlayer,
- createAudioResource,
- getVoiceConnection,
- joinVoiceChannel,
- VoiceConnectionStatus
-} from '@discordjs/voice';
-import { EmbedBuilder } from 'discord.js';
-import { readdirSync, readFileSync, writeFile } from 'node:fs';
-import { parseFile } from 'music-metadata';
-
-// import config from './config.json' assert {type: 'json'}
-const { voiceChannel, statusChannel, shuffle, txtFile } = JSON.parse(readFileSync('./config.json'));
-
-export const player = createAudioPlayer();
-export let audio;
-export const files = readdirSync('music');
-let fileData;
-
-let totalTrack = files.length;
-export let currentTrack;
-
-export let duration;
-export let playerState;
-export let isAudioStatePaused;
-export let metadataEmpty = false;
-
-export let audioTitle;
-export let audioArtist;
-export let audioYear;
-export let audioAlbum;
-
-export async function voiceInit(bot) {
- bot.channels.fetch(voiceChannel).then(async channel => {
- const connection = joinVoiceChannel({
- channelId: channel.id,
- guildId: channel.guild.id,
- adapterCreator: channel.guild.voiceAdapterCreator
- });
-
- connection.on(VoiceConnectionStatus.Ready, async() => {
- console.log('Ready to blast some beats!');
- return (shuffle === true) ? await shufflePlaylist(bot) : await orderPlaylist(bot);
- });
-
- connection.on(VoiceConnectionStatus.Destroyed, () => {
- console.log('Destroyed the beats...');
- });
-
- player.on('error', error => {
- console.error(error);
- nextAudio(bot);
- });
-
- player.on('idle', () => {
- console.log('Beat has finished playing, now playing next beat...');
- nextAudio(bot);
- });
-
- return connection.subscribe(player);
- }).catch(e => { console.error(e); });
-}
-
-function shuffleArray(array) {
- 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]];
- }
-}
-
-export async function orderPlaylist(bot) {
- console.log('Playing beats by order...');
- currentTrack = 0;
- console.log(files);
- audio = files[currentTrack];
- return await playAudio(bot);
-}
-
-export async function shufflePlaylist(bot) {
- console.log('Shuffling beats...');
- shuffleArray(files);
- console.log('Playing beats by shuffle...');
- currentTrack = 0;
- console.log(files);
- audio = files[currentTrack];
- return await playAudio(bot);
-}
-
-export async function nextAudio(bot) {
- totalTrack--;
- if (currentTrack >= totalTrack) {
- console.log('All beats in the playlist has finished, repeating beats...');
- return (shuffle === true) ? await shufflePlaylist(bot) : await orderPlaylist(bot);
- } else {
- currentTrack++;
- audio = files[currentTrack];
- return await playAudio(bot);
- }
-}
-
-export async function previousAudio(bot, interaction) {
- totalTrack++
- if (currentTrack <= 0) {
- return await interaction.reply({ content: 'You are at the beginning of the playlist, cannot go further than this', ephemeral: true });
- } else {
- await interaction.reply({ content: 'Playing previous music', ephemeral: true });
- player.stop();
- currentTrack--;
- audio = files[currentTrack];
- return await playAudio(bot);
- }
-}
-
-export async function inputAudio(bot, integer) {
- const inputFiles = readdirSync('music');
- audio = inputFiles[integer];
- return await playAudio(bot);
-}
-
-export async function playAudio(bot) {
- const resource = createAudioResource('music/' + audio);
-
- player.play(resource);
-
- console.log('Now playing: ' + audio);
-
- playerState = 'Playing';
- isAudioStatePaused = false;
-
- let audioFile = audio;
-
- try {
- const { common, format } = await parseFile('music/' + audio);
- metadataEmpty = false;
- if (common.title && common.artist && common.year && common.album) {
- audioTitle = common.title;
- audioArtist = common.artist;
- audioYear = common.year;
- audioAlbum = common.album;
- } else {
- metadataEmpty = true;
- }
- const toHHMMSS = (numSecs) => {
- const secNum = parseInt(numSecs, 10);
- const hours = Math.floor(secNum / 3600).toString().padStart(2, '0');
- const minutes = Math.floor((secNum - (hours * 3600)) / 60).toString().padStart(2, '0'); ;
- const seconds = secNum - (hours * 3600) - (minutes * 60).toString().padStart(2, '0'); ;
- return `${hours}:${minutes}:${seconds}`;
- };
- duration = toHHMMSS(format.duration);
- } catch (e) {
- console.error(e);
- }
-
- audio = audio.split('.').slice(0, -1).join('.');
-
- if (txtFile === true) {
- fileData = 'Now Playing: ' + audio;
- writeFile('./now-playing.txt', fileData, (err) => {
- if (err) { console.log(err); }
- });
- }
-
- const statusEmbed = new EmbedBuilder();
- if (metadataEmpty === true) {
- statusEmbed.setTitle('Now Playing')
- statusEmbed.addFields(
- { name: 'Title', value: audio },
- { name: 'Duration', value: duration }
- );
- statusEmbed.setColor('#0066ff');
- } else {
- statusEmbed.setTitle('Now Playing');
- statusEmbed.addFields(
- { name: 'Title', value: audioTitle, inline: true },
- { name: 'Artist', value: audioArtist, inline: true },
- { name: 'Year', value: `${audioYear}` },
- { name: 'Duration', value: duration }
- );
- statusEmbed.setFooter({ text: `Album: ${audioAlbum} | Filename: ${audioFile}` });
- statusEmbed.setColor('#0066ff');
- }
- const channel = bot.channels.cache.get(statusChannel);
- if (!channel) return console.error('The status channel does not exist! Skipping.');
- return await channel.send({ embeds: [statusEmbed] });
-}
-
-export async function destroyAudio(interaction) {
- if (txtFile === true) {
- fileData = 'Now Playing: Nothing';
- writeFile('now-playing.txt', fileData, (err) => {
- if (err) { console.log(err); }
- });
- }
-
- audio = 'Not Playing';
- playerState = 'Stopped';
- isAudioStatePaused = true;
-
- const connection = getVoiceConnection(interaction.guild.id);
- if (VoiceConnectionStatus.Ready) {
- player.stop();
- return connection.destroy();
- }
-}
-
-export function audioState() {
- if (isAudioStatePaused === false) {
- isAudioStatePaused = true;
- playerState = 'Paused';
- } else if (isAudioStatePaused === true) {
- isAudioStatePaused = false;
- playerState = 'Playing';
- }
-}
-
-export async function stopBot(bot, interaction) {
- const statusEmbed = new EmbedBuilder()
- .setAuthor({ name: bot.user.username, iconURL: bot.user.avatarURL() })
- .setDescription(`That's all folks! Powering down ${bot.user.username}...`)
- .setColor('#0066ff');
- const channel = bot.channels.cache.get(statusChannel);
- if (!channel) return console.error('The status channel does not exist! Skipping.');
- await channel.send({ embeds: [statusEmbed] });
-
- console.log(`Powering off ${bot.user.username}...`);
- await destroyAudio(interaction);
- bot.destroy();
- return process.exit(0);
-}
diff --git a/README.md b/README.md
index 15aec6a..6f46bb5 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,8 @@ A Discord bot that plays local audio tracks. Written in Discord.JS v14.
If you want to add a feature or there's anything wrong, feel free to make a fork and put a pull request.
-# Recommended Software
-- Latest version of NodeJS (v18.5.0+)
+# Recommended Software Requirements
+- Latest version of NodeJS (v16.9.0+)
- Linux (or WSL for Windows users)
# Configuration
@@ -56,7 +56,7 @@ shutdown - Powers off the bot.
# Forking
When forking the project, you can make your own version of DLAP or help contribute to the project (See the "Contributing" section).
-You need to edit `/commands/about.js` to uncomment the `.addFields({ name: 'Forked by', value: '[your name] (discord#0000)' })` section.
+You need to edit `/commands/about.js` to uncomment the `{ name: 'Forked by', value: '[your name] (discord#0000)' }` section.
Be sure to replace that with your name.
diff --git a/backend/AudioControl.js b/backend/AudioControl.js
new file mode 100644
index 0000000..f26d9d1
--- /dev/null
+++ b/backend/AudioControl.js
@@ -0,0 +1,82 @@
+/**************************************************************************
+ *
+ * DLAP Bot: A Discord bot that plays local audio tracks.
+ * (C) Copyright 2022
+ * Programmed by Andrew Lee
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ ***************************************************************************/
+import { readdirSync, readFileSync } from 'node:fs';
+import { shufflePlaylist, orderPlaylist } from './QueueSystem.js';
+import { playAudio, currentTrack, updatePlaylist } from './PlayAudio.js';
+import { player } from './VoiceInitialization.js';
+
+const { shuffle } = JSON.parse(readFileSync('./config.json', 'utf-8'));
+export const files = readdirSync('music');
+export let playerState;
+export let isAudioStatePaused;
+
+let totalTrack = files.length;
+
+export async function nextAudio(bot) {
+ totalTrack--;
+ if (currentTrack >= totalTrack) {
+ console.log('All beats in the playlist has finished, repeating beats...');
+ totalTrack = files.length;
+ return (shuffle === true) ? await shufflePlaylist(bot) : await orderPlaylist(bot);
+ } else {
+ updatePlaylist('next');
+ return await playAudio(bot);
+ }
+}
+
+export async function previousAudio(bot, interaction) {
+ totalTrack++;
+ if (currentTrack <= 0) {
+ return await interaction.reply({ content: 'You are at the beginning of the playlist, cannot go further than this', ephemeral: true });
+ } else {
+ await interaction.reply({ content: 'Playing previous music', ephemeral: true });
+ player.stop();
+ updatePlaylist('back');
+ return await playAudio(bot);
+ }
+}
+
+export function toggleAudioState() {
+ if (isAudioStatePaused === true) {
+ audioState(0);
+ } else {
+ audioState(1);
+ }
+}
+
+export function audioState(state) {
+ switch (state) {
+ case 0:
+ playerState = 'Playing';
+ isAudioStatePaused = false;
+ player.unpause();
+ break;
+ case 1:
+ playerState = 'Paused';
+ isAudioStatePaused = true;
+ player.pause();
+ break;
+ case 2:
+ playerState = 'Stopped';
+ isAudioStatePaused = true;
+ break;
+ }
+}
diff --git a/backend/PlayAudio.js b/backend/PlayAudio.js
new file mode 100644
index 0000000..77a33bc
--- /dev/null
+++ b/backend/PlayAudio.js
@@ -0,0 +1,128 @@
+/**************************************************************************
+ *
+ * DLAP Bot: A Discord bot that plays local audio tracks.
+ * (C) Copyright 2022
+ * Programmed by Andrew Lee
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ ***************************************************************************/
+import { createAudioResource } from '@discordjs/voice';
+import { parseFile } from 'music-metadata';
+import { readdirSync, readFileSync, writeFile } from 'node:fs';
+import { EmbedBuilder } from 'discord.js';
+import { player } from './VoiceInitialization.js';
+import { audioState, files } from './AudioControl.js';
+import { integer } from '../commands/play.js';
+const { statusChannel, txtFile } = JSON.parse(readFileSync('./config.json', 'utf-8'));
+
+let fileData;
+export let audio;
+export let duration;
+export let metadataEmpty = false;
+export let audioTitle;
+export let audioArtist;
+export let audioYear;
+export let audioAlbum;
+export let currentTrack;
+
+const inputFiles = readdirSync('music');
+export async function playAudio(bot) {
+ const resource = createAudioResource('music/' + audio);
+ player.play(resource);
+
+ console.log('Now playing: ' + audio);
+
+ audioState(0);
+
+ const audioFile = audio;
+
+ try {
+ const { common, format } = await parseFile('music/' + audio);
+ metadataEmpty = false;
+ if (common.title && common.artist && common.year && common.album) {
+ audioTitle = common.title;
+ audioArtist = common.artist;
+ audioYear = common.year;
+ audioAlbum = common.album;
+ } else {
+ metadataEmpty = true;
+ }
+ const toHHMMSS = (numSecs) => {
+ const secNum = parseInt(numSecs, 10);
+ const hours = Math.floor(secNum / 3600).toString().padStart(2, '0');
+ const minutes = Math.floor((secNum - (hours * 3600)) / 60).toString().padStart(2, '0');
+ const seconds = secNum - (hours * 3600) - (minutes * 60).toString().padStart(2, '0');
+ return `${hours}:${minutes}:${seconds}`;
+ };
+ duration = toHHMMSS(format.duration);
+ } catch (e) {
+ console.error(e);
+ }
+
+ audio = audio.split('.').slice(0, -1).join('.');
+
+ if (txtFile === true) {
+ fileData = 'Now Playing: ' + audio;
+ writeFile('./now-playing.txt', fileData, (err) => {
+ if (err) { console.log(err); }
+ });
+ }
+
+ const statusEmbed = new EmbedBuilder();
+ if (metadataEmpty === true) {
+ statusEmbed.setTitle('Now Playing');
+ statusEmbed.addFields(
+ { name: 'Title', value: audio },
+ { name: 'Duration', value: duration }
+ );
+ statusEmbed.setColor('#0066ff');
+ } else {
+ statusEmbed.setTitle('Now Playing');
+ statusEmbed.addFields(
+ { name: 'Title', value: audioTitle, inline: true },
+ { name: 'Artist', value: audioArtist, inline: true },
+ { name: 'Year', value: `${audioYear}` },
+ { name: 'Duration', value: duration }
+ );
+ statusEmbed.setFooter({ text: `Album: ${audioAlbum}\nFilename: ${audioFile}` });
+ statusEmbed.setColor('#0066ff');
+ }
+ const channel = bot.channels.cache.get(statusChannel);
+ if (!channel) return console.error('The status channel does not exist! Skipping.');
+ return await channel.send({ embeds: [statusEmbed] });
+}
+
+export function updatePlaylist(i) {
+ switch (i) {
+ case 'next':
+ currentTrack++;
+ audio = files[currentTrack];
+ break;
+ case 'back':
+ currentTrack--;
+ audio = files[currentTrack];
+ break;
+ case 'reset':
+ currentTrack = 0;
+ audio = files[currentTrack];
+ break;
+ case 'input':
+ audio = inputFiles[integer];
+ break;
+ case 'stop':
+ audio = 'Not Playing';
+ break;
+ }
+}
diff --git a/backend/QueueSystem.js b/backend/QueueSystem.js
new file mode 100644
index 0000000..0cd6ded
--- /dev/null
+++ b/backend/QueueSystem.js
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * DLAP Bot: A Discord bot that plays local audio tracks.
+ * (C) Copyright 2022
+ * Programmed by Andrew Lee
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ ***************************************************************************/
+import { playAudio, updatePlaylist } from './PlayAudio.js';
+import { files } from './AudioControl.js';
+
+function shuffleArray(array) {
+ // Durstenfeld Shuffle
+ 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]];
+ }
+}
+export async function orderPlaylist(bot) {
+ console.log('Playing beats by order...');
+ updatePlaylist('reset');
+ console.log(files);
+ return await playAudio(bot);
+}
+
+export async function shufflePlaylist(bot) {
+ console.log('Shuffling beats...');
+ shuffleArray(files);
+ console.log('Playing beats by shuffle...');
+ updatePlaylist('reset');
+ console.log(files);
+ return await playAudio(bot);
+}
+
+export async function inputAudio(bot) {
+ updatePlaylist('input');
+ return await playAudio(bot);
+}
diff --git a/backend/Shutdown.js b/backend/Shutdown.js
new file mode 100644
index 0000000..641ca1e
--- /dev/null
+++ b/backend/Shutdown.js
@@ -0,0 +1,60 @@
+/**************************************************************************
+ *
+ * DLAP Bot: A Discord bot that plays local audio tracks.
+ * (C) Copyright 2022
+ * Programmed by Andrew Lee
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ ***************************************************************************/
+import { EmbedBuilder } from 'discord.js';
+import { player } from './VoiceInitialization.js';
+import { updatePlaylist } from './PlayAudio.js';
+import { audioState } from './AudioControl.js';
+import { readFileSync, writeFile } from 'node:fs';
+import { getVoiceConnection, VoiceConnectionStatus } from '@discordjs/voice';
+const { statusChannel, txtFile } = JSON.parse(readFileSync('./config.json', 'utf-8'));
+let fileData;
+
+export async function destroyAudio(interaction) {
+ if (txtFile === true) {
+ fileData = 'Now Playing: Nothing';
+ writeFile('now-playing.txt', fileData, (err) => {
+ if (err) { console.log(err); }
+ });
+ }
+
+ updatePlaylist('stop');
+ audioState(2);
+
+ const connection = getVoiceConnection(interaction.guild.id);
+ if (VoiceConnectionStatus.Ready) {
+ player.stop();
+ return connection.destroy();
+ }
+}
+export async function stopBot(bot, interaction) {
+ const statusEmbed = new EmbedBuilder()
+ .setAuthor({ name: bot.user.username, iconURL: bot.user.avatarURL() })
+ .setDescription(`That's all folks! Powering down ${bot.user.username}...`)
+ .setColor('#0066ff');
+ const channel = bot.channels.cache.get(statusChannel);
+ if (!channel) return console.error('The status channel does not exist! Skipping.');
+ await channel.send({ embeds: [statusEmbed] });
+
+ console.log(`Powering off ${bot.user.username}...`);
+ await destroyAudio(interaction);
+ bot.destroy();
+ return process.exit(0);
+}
diff --git a/backend/VoiceInitialization.js b/backend/VoiceInitialization.js
new file mode 100644
index 0000000..61d4734
--- /dev/null
+++ b/backend/VoiceInitialization.js
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * DLAP Bot: A Discord bot that plays local audio tracks.
+ * (C) Copyright 2022
+ * Programmed by Andrew Lee
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ ***************************************************************************/
+import { readFileSync } from 'node:fs';
+import { createAudioPlayer, joinVoiceChannel, VoiceConnectionStatus } from '@discordjs/voice';
+import { nextAudio } from './AudioControl.js';
+import { shufflePlaylist, orderPlaylist } from './QueueSystem.js';
+
+const { voiceChannel, shuffle } = JSON.parse(readFileSync('./config.json', 'utf-8'));
+export const player = createAudioPlayer();
+export async function voiceInit(bot) {
+ bot.channels.fetch(voiceChannel).then(async channel => {
+ const connection = joinVoiceChannel({
+ channelId: channel.id,
+ guildId: channel.guild.id,
+ adapterCreator: channel.guild.voiceAdapterCreator
+ });
+
+ connection.on(VoiceConnectionStatus.Ready, async() => {
+ console.log('Ready to blast some beats!');
+ return (shuffle === true) ? await shufflePlaylist(bot) : await orderPlaylist(bot);
+ });
+
+ connection.on(VoiceConnectionStatus.Destroyed, () => {
+ console.log('Destroyed the beats...');
+ });
+
+ player.on('error', error => {
+ console.error(error);
+ nextAudio(bot);
+ });
+
+ player.on('idle', () => {
+ console.log('Beat has finished playing, now playing next beat...');
+ nextAudio(bot);
+ });
+
+ return connection.subscribe(player);
+ }).catch(e => { console.error(e); });
+}
diff --git a/bot.js b/bot.js
index abb893c..4aa909b 100644
--- a/bot.js
+++ b/bot.js
@@ -19,10 +19,10 @@
*
***************************************************************************/
import { Client, GatewayIntentBits, EmbedBuilder, Collection, version, InteractionType } from 'discord.js';
-import { voiceInit } from './AudioBackend.js';
+import { voiceInit } from './backend/VoiceInitialization.js';
import { readdirSync, readFileSync } from 'node:fs';
// import config from './config.json' assert { type: 'json' } Not supported by ESLint yet
-const { token, statusChannel, voiceChannel, shuffle } = JSON.parse(readFileSync('./config.json'));
+const { token, statusChannel, voiceChannel, shuffle } = JSON.parse(readFileSync('./config.json', 'utf-8'));
const bot = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildVoiceStates] });
bot.login(token);
@@ -31,6 +31,7 @@ bot.login(token);
* TODO: - Custom string support (Basically change what the bot is saying)
* - Non repeat support
* - Modularizing AudioBackend
+ * - Easier to use interface
*/
// Slash Command Handler
diff --git a/commands/about.js b/commands/about.js
index 442cb48..e102a3e 100644
--- a/commands/about.js
+++ b/commands/about.js
@@ -39,7 +39,7 @@ export default {
// { name: 'Forked by', value: '[your name] (discord#0000)' },
{ name: 'Frameworks', value: `Discord.JS ${version} + Voice` },
{ name: 'License', value: 'GNU General Public License v3.0' }
- )
+ )
.setFooter({ text: '© Copyright 2020-2022 Andrew Lee' })
.setColor('#0066ff');
diff --git a/commands/join.js b/commands/join.js
index 7294724..c5f686d 100644
--- a/commands/join.js
+++ b/commands/join.js
@@ -20,7 +20,7 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { voiceInit } from '../AudioBackend.js';
+import { voiceInit } from '../backend/VoiceInitialization.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
diff --git a/commands/leave.js b/commands/leave.js
index 10634af..781bc0a 100644
--- a/commands/leave.js
+++ b/commands/leave.js
@@ -20,7 +20,7 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { destroyAudio } from '../AudioBackend.js';
+import { destroyAudio } from '../backend/Shutdown.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
diff --git a/commands/next.js b/commands/next.js
index 01c5df9..b507cd1 100644
--- a/commands/next.js
+++ b/commands/next.js
@@ -20,7 +20,8 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { player, nextAudio } from '../AudioBackend.js';
+import { player } from '../backend/VoiceInitialization.js';
+import { nextAudio } from '../backend/AudioControl.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
diff --git a/commands/pause.js b/commands/pause.js
index dffcfb5..d5d8edc 100644
--- a/commands/pause.js
+++ b/commands/pause.js
@@ -20,7 +20,7 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { audioState, isAudioStatePaused, player } from '../AudioBackend.js';
+import { toggleAudioState, isAudioStatePaused } from '../backend/AudioControl.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
@@ -30,8 +30,7 @@ export default {
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
async execute(interaction) {
if (isAudioStatePaused === false) {
- audioState();
- player.pause();
+ toggleAudioState();
return await interaction.reply({ content: 'Pausing music', ephemeral: true });
} else {
return await interaction.reply({ content: 'Music is already paused', ephemeral: true });
diff --git a/commands/play.js b/commands/play.js
index f9701f7..fd8132c 100644
--- a/commands/play.js
+++ b/commands/play.js
@@ -20,7 +20,9 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { isAudioStatePaused, inputAudio, audio, audioState, player, files } from '../AudioBackend.js';
+import { inputAudio } from '../backend/QueueSystem.js';
+import { files, isAudioStatePaused, toggleAudioState } from '../backend/AudioControl.js';
+import { audio } from '../backend/PlayAudio.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export let integer;
@@ -46,8 +48,7 @@ export default {
}
}
if (isAudioStatePaused === true) {
- audioState();
- player.unpause();
+ toggleAudioState();
return await interaction.reply({ content: 'Resuming music', ephemeral: true });
} else {
return await interaction.reply({ content: 'Music is already playing', ephemeral: true });
diff --git a/commands/previous.js b/commands/previous.js
index 2bb8960..6d5eff3 100644
--- a/commands/previous.js
+++ b/commands/previous.js
@@ -20,7 +20,7 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { previousAudio } from '../AudioBackend.js';
+import { previousAudio } from '../backend/AudioControl.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
diff --git a/commands/reshuffle.js b/commands/reshuffle.js
index 8de2d17..517c272 100644
--- a/commands/reshuffle.js
+++ b/commands/reshuffle.js
@@ -20,11 +20,12 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { player, shufflePlaylist } from '../AudioBackend.js';
+import { player } from '../backend/VoiceInitialization.js';
+import { shufflePlaylist } from '../backend/QueueSystem.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
import { readFileSync } from 'node:fs';
// import config from './config.json' assert {type: 'json'}
-const { shuffle } = JSON.parse(readFileSync('./config.json'));
+const { shuffle } = JSON.parse(readFileSync('./config.json', 'utf-8'));
export default {
data: new SlashCommandBuilder()
diff --git a/commands/shutdown.js b/commands/shutdown.js
index 0cf75b8..313866b 100644
--- a/commands/shutdown.js
+++ b/commands/shutdown.js
@@ -20,7 +20,7 @@
***************************************************************************/
import { SlashCommandBuilder } from 'discord.js';
-import { stopBot } from '../AudioBackend.js';
+import { stopBot } from '../backend/Shutdown.js';
import { PermissionFlagsBits } from 'discord-api-types/v10';
export default {
diff --git a/commands/status.js b/commands/status.js
index 958a359..3143e16 100644
--- a/commands/status.js
+++ b/commands/status.js
@@ -21,7 +21,8 @@
import { EmbedBuilder, SlashCommandBuilder } from 'discord.js';
import { parseFile } from 'music-metadata';
-import { audio, currentTrack, files, playerState, audioTitle, metadataEmpty, duration } from '../AudioBackend.js';
+import { audio, metadataEmpty, duration, audioTitle, currentTrack } from '../backend/PlayAudio.js';
+import { files, playerState } from '../backend/AudioControl.js';
export default {
data: new SlashCommandBuilder()
@@ -54,7 +55,7 @@ export default {
{ name: 'State', value: playerState },
{ name: 'Tracks', value: `${audioID}/${files.length}` },
{ name: 'Duration', value: duration }
- )
+ )
.setColor('#0066ff');
if (metadataEmpty === true) {