Pause resume loop & progress bar with message #1

Merged
Myxelium merged 5 commits from pause-resume-loop into master 2023-06-26 00:40:13 +00:00
9 changed files with 197 additions and 59 deletions
Showing only changes of commit f09c13ac03 - Show all commits

17
commands/loop.js Normal file
View File

@@ -0,0 +1,17 @@
const musicQueue = require('../musicQueue');
async function loopCommand(interaction) {
await interaction.deferReply();
const looping = interaction.options.getBoolean('looping');
musicQueue.setLooping(interaction.guild.id, looping);
if (looping) {
interaction.followUp('Enabled looping for the current queue.');
} else {
interaction.followUp('Disabled looping for the current queue.');
}
}
module.exports.loopCommand = loopCommand;

32
commands/pause.js Normal file
View File

@@ -0,0 +1,32 @@
const { musicPlayer } = require('../utils/musicPlayer');
const { AudioPlayerStatus, joinVoiceChannel, AudioPlayerState } = require('@discordjs/voice');
async function pauseCommand(interaction) {
await interaction.deferReply();
const voiceChannel = interaction.member.voice.channel;
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false
});
let player = await musicPlayer(interaction.guild.id, connection, false);
if (!voiceChannel) {
return interaction.followUp('You must be in a voice channel to use this command.');
}
if (!player) {
return interaction.followUp('I am not currently playing music in a voice channel.');
}
// player.pause();
interaction.followUp('Paused the music.');
}
module.exports.pauseCommand = pauseCommand;

35
commands/play.js Normal file
View File

@@ -0,0 +1,35 @@
const { getMusicStream } = require('./../utils/getMusicStream');
const musicQueue = require('../musicQueue');
const { musicPlayer } = require('../utils/musicPlayer');
const {
joinVoiceChannel,
} = require('@discordjs/voice');
async function playCommand(interaction) {
await interaction.deferReply();
const query = interaction.options.getString('input');
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.followUp('You must be in a voice channel to use this command.');
}
const song = await getMusicStream(query);
musicQueue.addToQueue(interaction.guild.id, song);
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false
});
musicPlayer(interaction.guild.id, connection);
interaction.followUp(`Added ${song.title} to the queue.`);
}
module.exports.playCommand = playCommand;

32
commands/resume.js Normal file
View File

@@ -0,0 +1,32 @@
const { musicPlayer } = require('../utils/musicPlayer');
const { joinVoiceChannel } = require('@discordjs/voice');
async function resumeCommand(interaction) {
await interaction.deferReply();
const voiceChannel = interaction.member.voice.channel;
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false
});
let player = await musicPlayer(interaction.guild.id, connection, false);
if (!voiceChannel) {
return interaction.followUp('You must be in a voice channel to use this command.');
}
if (!player) {
return interaction.followUp('I am not currently playing music in a voice channel.');
}
player.unpause();
interaction.followUp('Resumed the music.');
}
module.exports.resumeCommand = resumeCommand;

View File

@@ -1,9 +1,12 @@
const { playCommand } = require('./play.js');
const { Client, GatewayIntentBits } = require('discord.js'); const { Client, GatewayIntentBits } = require('discord.js');
const { queueCommand } = require('./commands/queue');
const { registerCommands } = require('./utils/registerCommands'); const { registerCommands } = require('./utils/registerCommands');
const process = require('dotenv').config(); const { playCommand } = require('./commands/play');
const { queueCommand } = require('./commands/queue');
const { pauseCommand } = require('./commands/pause');
const { resumeCommand } = require('./commands/resume');
const { loopCommand } = require('./commands/loop');
const process = require('dotenv').config();
const clientId = process.parsed.clientId; const clientId = process.parsed.clientId;
const token = process.parsed.token; const token = process.parsed.token;
@@ -31,8 +34,14 @@ client.on('interactionCreate', async (interaction) => {
await playCommand(interaction); await playCommand(interaction);
} else if (commandName === 'queue') { } else if (commandName === 'queue') {
await queueCommand(interaction); await queueCommand(interaction);
} else if (commandName === 'pause') {
await pauseCommand(interaction);
} else if (commandName === 'resume') {
await resumeCommand(interaction);
} else if (commandName === 'loop') {
await loopCommand(interaction);
} }
}); });
// client.login(process.env.TOKEN); // client.login(process.env.TOKEN);

View File

@@ -1,24 +1,42 @@
class MusicQueue { class MusicQueue {
constructor() { constructor() {
this.queue = new Map(); this.queue = new Map();
} this.looping = new Map();
getQueue(guildId) {
if (!this.queue.has(guildId)) {
this.queue.set(guildId, []);
}
return this.queue.get(guildId);
} }
addToQueue(guildId, song) { addToQueue(guildId, song) {
const serverQueue = this.getQueue(guildId); if (!this.queue.has(guildId)) {
serverQueue.push(song); this.queue.set(guildId, []);
}
this.queue.get(guildId).push(song);
} }
removeFromQueue(guildId) { removeFromQueue(guildId) {
const serverQueue = this.getQueue(guildId); if (!this.queue.has(guildId)) {
return;
}
const serverQueue = this.queue.get(guildId);
if (this.looping.has(guildId) && this.looping.get(guildId)) {
serverQueue.push(serverQueue.shift());
} else {
serverQueue.shift(); serverQueue.shift();
} }
} }
module.exports = new MusicQueue(); getQueue(guildId) {
if (!this.queue.has(guildId)) {
return [];
}
return this.queue.get(guildId);
}
setLooping(guildId, looping) {
this.looping.set(guildId, looping);
}
}
module.exports = new MusicQueue();

View File

@@ -24,10 +24,10 @@ async function getMusicStream(query) {
type = StreamType.OggOpus; type = StreamType.OggOpus;
} else { } else {
stream = await youtube.getStream(query); stream = await youtube.getStream(query)
songTitle = stream.title ?? 'Unknown'; songTitle = stream?.title ?? 'Unknown';
songDuration = stream.duration ?? 'Unknown'; songDuration = stream?.duration ?? 'Unknown';
stream = stream.stream; stream = stream?.stream;
type = StreamType.Opus; type = StreamType.Opus;
} }

View File

@@ -1,40 +1,12 @@
const { const {
joinVoiceChannel,
createAudioResource, createAudioResource,
createAudioPlayer, createAudioPlayer,
NoSubscriberBehavior, NoSubscriberBehavior,
AudioPlayerStatus, AudioPlayerStatus,
} = require('@discordjs/voice'); } = require('@discordjs/voice');
const musicQueue = require('./musicQueue'); const musicQueue = require('../musicQueue');
const { getMusicStream } = require('./utils/getMusicStream');
async function playCommand(interaction) { async function musicPlayer(guildId, connection) {
await interaction.deferReply();
const query = interaction.options.getString('input');
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.followUp('You must be in a voice channel to use this command.');
}
const song = await getMusicStream(query);
musicQueue.addToQueue(interaction.guild.id, song);
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false
});
playSong(interaction.guild.id, connection);
interaction.followUp(`Added ${song.title} to the queue.`);
}
async function playSong(guildId, connection) {
const serverQueue = musicQueue.getQueue(guildId); const serverQueue = musicQueue.getQueue(guildId);
if (serverQueue.length === 0) { if (serverQueue.length === 0) {
@@ -44,6 +16,12 @@ async function playCommand(interaction) {
const song = serverQueue[0]; const song = serverQueue[0];
if(song.stream == null){
musicQueue.removeFromQueue(guildId);
musicPlayer(guildId, connection);
return;
}
let resource = createAudioResource(song.stream, { let resource = createAudioResource(song.stream, {
inputType: song.type inputType: song.type
}) })
@@ -54,6 +32,7 @@ async function playCommand(interaction) {
} }
}) })
player.play(resource) player.play(resource)
connection.subscribe(player) connection.subscribe(player)
@@ -61,8 +40,10 @@ async function playCommand(interaction) {
player.on(AudioPlayerStatus.Idle, () => { player.on(AudioPlayerStatus.Idle, () => {
console.log('Song ended:', song.title); console.log('Song ended:', song.title);
musicQueue.removeFromQueue(guildId); musicQueue.removeFromQueue(guildId);
playSong(guildId, connection); musicPlayer(guildId, connection);
}); });
return player;
} }
// TODO: USE THIS AGAIN // TODO: USE THIS AGAIN
@@ -83,4 +64,4 @@ function convertToMilliseconds(songLenth) {
} }
} }
module.exports.playCommand = playCommand; module.exports.musicPlayer = musicPlayer;

View File

@@ -19,6 +19,20 @@ async function registerCommands(clientId, token) {
option.setName('song') option.setName('song')
.setDescription('Add song from YouTube, Spotify, SoundCloud, etc. to the queue') .setDescription('Add song from YouTube, Spotify, SoundCloud, etc. to the queue')
.setRequired(true) .setRequired(true)
),
new SlashCommandBuilder()
.setName('pause')
.setDescription('Pauses the current song!'),
new SlashCommandBuilder()
.setName('resume')
.setDescription('Resumes the current song!'),
new SlashCommandBuilder()
.setName('loop')
.setDescription('Loops the current song!')
.addBooleanOption(option =>
option.setName('looping')
.setDescription('Enable or disable looping')
.setRequired(true)
) )
]; ];