aboutsummaryrefslogtreecommitdiff
path: root/AudioBackend
diff options
context:
space:
mode:
authorAndrew Lee <alee14498@protonmail.com>2022-12-18 22:31:04 -0500
committerAndrew Lee <alee14498@protonmail.com>2022-12-18 22:36:32 -0500
commitc55e480e4d8dbf9d3c11cb7a13c69f9f1ab730db (patch)
tree848c4cdc3e1efb003cc7dacf3f3670ae62562fa0 /AudioBackend
parent4c25284974a1575b942e3d07bf00afa2614cd376 (diff)
downloadDLAP-c55e480e4d8dbf9d3c11cb7a13c69f9f1ab730db.tar.gz
DLAP-c55e480e4d8dbf9d3c11cb7a13c69f9f1ab730db.tar.bz2
DLAP-c55e480e4d8dbf9d3c11cb7a13c69f9f1ab730db.zip
Improved list command; Directory name change; Fixed ActivityType
Diffstat (limited to 'AudioBackend')
-rw-r--r--AudioBackend/AudioControl.js92
-rw-r--r--AudioBackend/PlayAudio.js124
-rw-r--r--AudioBackend/QueueSystem.js50
-rw-r--r--AudioBackend/Shutdown.js60
-rw-r--r--AudioBackend/VoiceInitialization.js61
5 files changed, 387 insertions, 0 deletions
diff --git a/AudioBackend/AudioControl.js b/AudioBackend/AudioControl.js
new file mode 100644
index 0000000..447e040
--- /dev/null
+++ b/AudioBackend/AudioControl.js
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * 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, repeat } = JSON.parse(readFileSync('./config.json', 'utf-8'));
+export const files = readdirSync('music');
+export let playerState;
+export let isAudioStatePaused;
+
+let totalTrack = files.length;
+
+async function repeatCheck(bot) {
+ if (repeat) {
+ console.log('All beats in the playlist has finished, repeating beats...');
+ totalTrack = files.length;
+ return (shuffle) ? await shufflePlaylist(bot) : await orderPlaylist(bot);
+ } else {
+ console.log('All beats in the playlist has finished.');
+ updatePlaylist('stop');
+ audioState(2);
+ }
+}
+
+export async function nextAudio(bot) {
+ if (currentTrack >= totalTrack - 1) {
+ await repeatCheck(bot);
+ } else {
+ updatePlaylist('next');
+ return await playAudio(bot);
+ }
+}
+
+export async function previousAudio(bot, interaction) {
+ 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) {
+ 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';
+ totalTrack = files.length;
+ isAudioStatePaused = true;
+ player.stop();
+ break;
+ }
+}
diff --git a/AudioBackend/PlayAudio.js b/AudioBackend/PlayAudio.js
new file mode 100644
index 0000000..5d18534
--- /dev/null
+++ b/AudioBackend/PlayAudio.js
@@ -0,0 +1,124 @@
+/**************************************************************************
+ *
+ * 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 currentTrack;
+
+export let metadataEmpty;
+
+export let audioTitle;
+export let audioArtist;
+export let audioYear;
+export let audioAlbum;
+export let duration;
+
+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;
+ }
+ duration = new Date(format.duration * 1000).toISOString().slice(11, 19);
+ } catch (e) {
+ console.error(e);
+ }
+
+ audio = audio.split('.').slice(0, -1).join('.');
+
+ if (txtFile) {
+ fileData = 'Now Playing: ' + audio;
+ writeFile('./now-playing.txt', fileData, (err) => {
+ if (err) { console.log(err); }
+ });
+ }
+
+ const statusEmbed = new EmbedBuilder();
+ if (metadataEmpty) {
+ 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(option) {
+ switch (option) {
+ 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/AudioBackend/QueueSystem.js b/AudioBackend/QueueSystem.js
new file mode 100644
index 0000000..0cd6ded
--- /dev/null
+++ b/AudioBackend/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/AudioBackend/Shutdown.js b/AudioBackend/Shutdown.js
new file mode 100644
index 0000000..fb89505
--- /dev/null
+++ b/AudioBackend/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) {
+ 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);
+ await bot.destroy();
+ return process.exit(0);
+}
diff --git a/AudioBackend/VoiceInitialization.js b/AudioBackend/VoiceInitialization.js
new file mode 100644
index 0000000..a9e1149
--- /dev/null
+++ b/AudioBackend/VoiceInitialization.js
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * 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.Connecting, () => {
+ console.log(`Connecting to ${channel.name}...`);
+ });
+
+ connection.on(VoiceConnectionStatus.Ready, async() => {
+ console.log('Ready to blast some beats!');
+ return (shuffle) ? 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); });
+}