14 Commits

Author SHA1 Message Date
cdb4ac3670 Update nowPlayingMessage.js 2023-07-09 12:30:00 +02:00
Myx
c7fcbc5a80 Refresh spotify token 2023-07-02 13:34:47 +02:00
Myx
398382a7f1 Add more commands 2023-07-02 01:57:55 +02:00
Myx
eccad8d147 Add bot status message 2023-06-29 04:05:52 +02:00
Myx
b19e6fb95c Leave on alone 2023-06-29 04:00:50 +02:00
e6f07d9713 Update maintenance.js 2023-06-29 03:44:58 +02:00
f7a386754a Delete .env 2023-06-29 02:34:54 +02:00
3ebf2568bf Update .gitignore 2023-06-29 02:34:20 +02:00
d5d51f15e2 Update maintenance.js 2023-06-29 02:27:53 +02:00
c8240b5a0d Update maintenance.js 2023-06-29 02:19:17 +02:00
b9524915e4 Update package.json 2023-06-29 02:18:37 +02:00
8eaef987fc Update package.json 2023-06-29 02:15:00 +02:00
b3789858f0 Create maintenance.js 2023-06-29 02:08:51 +02:00
97ae0215c5 Merge pull request #2 from Myxelium/pause-resume-loop
Halfbroken fixes
2023-06-28 03:04:32 +02:00
22 changed files with 464 additions and 109 deletions

2
.env
View File

@@ -1,2 +0,0 @@
token="MTExOTYyOTQwNzk5NzQwNzMwMg.GOuub1.r8FZ_DWaouO17vO2QpgcDI-zTh4iTuUrgNZRbY"
clientId="1119629407997407302"

View File

@@ -32,5 +32,6 @@ module.exports = {
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }], 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-duplicate-imports': ['error', { includeExports: true }], 'no-duplicate-imports': ['error', { includeExports: true }],
'eol-last': ['error', 'never'], 'eol-last': ['error', 'never'],
'linebreak-style': 0,
}, },
}; };

1
.gitignore vendored
View File

@@ -1 +1,2 @@
node_modules node_modules
.env

View File

@@ -3,7 +3,10 @@
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
"source.fixAll": true "source.fixAll": true
}, },
"eslint.validate": ["javascript"] "eslint.validate": [
"javascript"
],
"files.eol": "\n"
// "editor.formatOnSave": true, // "editor.formatOnSave": true,
// "eslint.format.enable": true // "eslint.format.enable": true

30
commands/leave.js Normal file
View File

@@ -0,0 +1,30 @@
// leaveCommand.js
const { getVoiceConnection } = require('@discordjs/voice');
const { intervalMap } = require('../utils/nowPlayingMessage'); // Import the intervalMap from the nowPlayingMessage module
const ConsolerLogger = require('../utils/logger');
const logger = new ConsolerLogger();
async function leaveCommand(interaction) {
await interaction.deferReply();
try {
const guildId = interaction.guild.id;
const connection = getVoiceConnection(guildId);
if (!connection) {
return interaction.followUp('I am not currently in a voice channel.');
}
// Clear the interval for updating the progress bar
const interval = intervalMap.get(guildId);
clearInterval(interval);
connection.destroy();
return interaction.followUp('I have left the voice channel.');
} catch (error) {
logger.error(error);
return interaction.followUp('An error occurred while trying to leave the voice channel.');
}
}
module.exports.leaveCommand = leaveCommand;

View File

@@ -27,10 +27,11 @@ async function playCommand(interaction) {
if (musicQueue.getQueue(interaction.guild.id).length > 0) { if (musicQueue.getQueue(interaction.guild.id).length > 0) {
musicQueue.removeFromQueue(interaction.guild.id); musicQueue.removeFromQueue(interaction.guild.id);
musicQueue.addToQueue(interaction.guild.id, song, true);
} else {
musicQueue.addToQueue(interaction.guild.id, song);
} }
musicQueue.addToQueue(interaction.guild.id, song);
musicPlayer( musicPlayer(
interaction.guild.id, interaction.guild.id,
connection, connection,

39
commands/previous.js Normal file
View File

@@ -0,0 +1,39 @@
const { joinVoiceChannel } = require('@discordjs/voice');
const musicQueue = require('../musicQueue');
const { musicPlayer } = require('../utils/musicPlayer');
function previousCommand(interaction) {
// Get the server queue
const serverQueue = musicQueue.getQueue(interaction.guild.id);
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.followUp(
'You must be in a voice channel to use this command.',
);
}
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false,
});
// Check if there is a previous song in the queue
if (serverQueue.previous === undefined) {
return interaction.reply('There is no previous song to go back to!');
}
// Add the previous song back to the front of the queue
musicQueue.addToQueue(interaction.guild.id, serverQueue.previous, true);
// Play the previous song
musicPlayer(interaction.guild.id, connection, interaction);
return interaction.reply('Went back to the previous song!');
}
module.exports.previousCommand = previousCommand;

40
commands/skip.js Normal file
View File

@@ -0,0 +1,40 @@
const { joinVoiceChannel } = require('@discordjs/voice');
const musicQueue = require('../musicQueue');
const { musicPlayer } = require('../utils/musicPlayer');
async function skipCommand(interaction) {
// Get the server queue
interaction.deferReply();
const serverQueue = musicQueue.getQueue(interaction.guild.id);
const voiceChannel = interaction.member.voice.channel;
if (!voiceChannel) {
return interaction.followUp(
'You must be in a voice channel to use this command.',
);
}
const connection = joinVoiceChannel({
channelId: voiceChannel.id,
guildId: interaction.guild.id,
adapterCreator: interaction.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false,
});
// Check if there are any songs in the queue
if (serverQueue.length === 0) {
return interaction.reply('There are no songs in the queue to skip!');
}
// Remove the current song from the queue
musicQueue.removeFromQueue(interaction.guild.id);
// Play the next song
await musicPlayer(interaction.guild.id, connection, interaction);
return interaction.reply('Skipped to the next song!');
}
module.exports.skipCommand = skipCommand;

View File

@@ -1,17 +1,23 @@
const { Client, GatewayIntentBits } = require('discord.js'); const { Client, GatewayIntentBits } = require('discord.js');
const process = require('dotenv').config(); const process = require('dotenv').config();
const { getVoiceConnection } = require('@discordjs/voice');
const { registerCommands } = require('./utils/registerCommands'); const { registerCommands } = require('./utils/registerCommands');
const { playCommand } = require('./commands/play'); const { playCommand } = require('./commands/play');
const { queueCommand } = require('./commands/queue'); const { queueCommand } = require('./commands/queue');
const { stopCommand } = require('./commands/stop'); const { stopCommand } = require('./commands/stop');
const { pauseCommand, unpauseCommand } = require('./commands/pauseResume'); const { pauseCommand, unpauseCommand } = require('./commands/pauseResume');
const { toggleLoopCommand } = require('./commands/loop'); const { toggleLoopCommand } = require('./commands/loop');
const { skipCommand } = require('./commands/skip');
const { leaveCommand } = require('./commands/leave');
const { previousCommand } = require('./commands/previous');
const { ReAuth } = require('./reAuthenticate'); const { ReAuth } = require('./reAuthenticate');
const ConsolerLogger = require('./utils/logger');
const { clientId } = process.parsed; const { clientId } = process.parsed;
const { token } = process.parsed; const { token } = process.parsed;
const client = new Client({ const logger = new ConsolerLogger();
const botClient = new Client({
intents: [ intents: [
GatewayIntentBits.Guilds, GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessages,
@@ -21,19 +27,31 @@ const client = new Client({
], ],
}); });
client.on('ready', async () => { botClient.on('ready', async () => {
console.log(`Logged in as ${client.user.tag}!`); logger.info(`Logged in as ${botClient.user.tag}!`);
botClient.user.setActivity('League of Legends', 0);
await registerCommands(clientId, token); await registerCommands(clientId, token);
}); });
client.on('interactionCreate', async (interaction) => { botClient.on('voiceStateUpdate', (oldState) => {
const voiceChannel = oldState.channel;
if (voiceChannel && voiceChannel.members.size === 1) {
const connection = getVoiceConnection(voiceChannel.guild.id);
if (connection) {
connection.disconnect();
connection.destroy();
}
}
});
botClient.on('interactionCreate', async (interaction) => {
if (!interaction.isCommand()) return; if (!interaction.isCommand()) return;
const { commandName } = interaction; const { commandName } = interaction;
if (commandName === 'play') { if (commandName === 'play') {
await playCommand(interaction, client); await playCommand(interaction, botClient);
} else if (commandName === 'queue') { } else if (commandName === 'queue') {
await queueCommand(interaction); await queueCommand(interaction);
} else if (commandName === 'pause') { } else if (commandName === 'pause') {
@@ -44,13 +62,21 @@ client.on('interactionCreate', async (interaction) => {
await toggleLoopCommand(interaction); await toggleLoopCommand(interaction);
} else if (commandName === 'stop') { } else if (commandName === 'stop') {
await stopCommand(interaction); await stopCommand(interaction);
} else if (commandName === 'leave') {
await leaveCommand(interaction);
} else if (commandName === 'skip') {
await skipCommand(interaction);
} else if (commandName === 'previous') {
await previousCommand(interaction);
} }
}); });
client.on('messageCreate', async (message) => { botClient.on('messageCreate', async (message) => {
if (message.content === 'reauth') { if (message.content === 'reauth') {
await ReAuth(); await ReAuth();
} }
}); });
client.login(token); botClient.login(token);
module.exports.botClient = { botClient };

47
maintenance.js Normal file
View File

@@ -0,0 +1,47 @@
/* eslint-disable no-shadow */
const { exec } = require('child_process');
const schedule = require('node-schedule');
const ConsolerLogger = require('./utils/logger');
const localRepoPath = '/home/pi/Lunaris/';
const processName = 'index.js';
const logger = new ConsolerLogger();
schedule.scheduleJob('0 1 * * *', () => {
exec(`cd ${localRepoPath} && git fetch`, (error) => {
if (error) {
logger.error(`exec error: ${error}`);
return;
}
exec(`cd ${localRepoPath} && git rev-list HEAD...origin/master --count`, (error, stdout) => {
if (error) {
logger.error(`exec error: ${error}`);
return;
}
if (parseInt(stdout, 10) > 0) {
exec(`pm2 stop ${processName}`, (error) => {
if (error) {
logger.error(`exec error: ${error}`);
return;
}
exec(`cd ${localRepoPath} && git pull`, (error) => {
if (error) {
logger.error(`exec error: ${error}`);
return;
}
const now = new Date();
logger.log(`Repository updated at ${now.toLocaleString()}`);
exec(`pm2 start ${processName}`, (error) => {
if (error) {
logger.error(`exec error: ${error}`);
return;
}
logger.log(`${processName} started`);
});
});
});
}
});
});
});

View File

@@ -6,12 +6,18 @@ class MusicQueue {
this.looping = new Map(); this.looping = new Map();
} }
addToQueue(guildId, song) { addToQueue(guildId, song, front = false) {
if (!this.queue.has(guildId)) { if (!this.queue.has(guildId)) {
this.queue.set(guildId, []); this.queue.set(guildId, []);
} }
this.queue.get(guildId).push(song); if (front) {
// Add the song to the front of the queue
this.queue.get(guildId).unshift(song);
} else {
// Add the song to the end of the queue
this.queue.get(guildId).push(song);
}
} }
async removeFromQueue(guildId) { async removeFromQueue(guildId) {
@@ -38,6 +44,15 @@ class MusicQueue {
return this.queue.get(guildId); return this.queue.get(guildId);
} }
async addToQueueFirst(guildId, song) {
if (!this.queue.has(guildId)) {
this.queue.set(guildId, []);
}
this.removeFromQueue(guildId);
this.queue.get(guildId).unshift(song);
}
enableLooping(guildId) { enableLooping(guildId) {
this.looping.set(guildId, true); this.looping.set(guildId, true);
} }

View File

@@ -1,14 +1,45 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
const playdl = require('play-dl'); const playdl = require('play-dl');
// TODO ADD SPOTIFY SUPPORT const youtube = require('./youtube');
async function getStream(query) { const musicQueue = require('../musicQueue');
async function getStream(query, guildId) {
if (playdl.is_expired()) {
await playdl.refreshToken();
}
if (playdl.sp_validate(query) === 'playlist') {
let firstTrack = {};
// Get the playlist information
const playlistInfo = await playdl.spotify(query);
// Loop through the tracks in the playlist
// Get the tracks from the fetched_tracks Map
const tracks = playlistInfo.fetched_tracks.get('1');
// Loop through the tracks in the playlist
for (const track of tracks) {
// save the first track in the queue
if (tracks.indexOf(track) === 0) {
firstTrack = await youtube.getStream(`${track.name} ${track.artists[0].name}`);
} else {
// Get a stream for the track using the youtube module
const song = await youtube.getStream(`${track.name} ${track.artists[0].name}`);
// Add the song to the music queue
musicQueue.addToQueue(guildId, song);
}
}
// Return null to indicate that a playlist was queued
return firstTrack;
}
// Handle single tracks as before
const trackInfo = await playdl.spotify(query); const trackInfo = await playdl.spotify(query);
return youtube.getStream(`${trackInfo.name} ${trackInfo.artists[0].name}`);
const searched = await play.search(`${trackInfo.name}`, {
limit: 1,
});
const stream = await play.stream(searched[0].url);
return stream;
} }
module.exports.getStream = getStream; module.exports.getStream = getStream;

View File

@@ -1,5 +1,8 @@
const ytsr = require('ytsr'); const ytsr = require('ytsr');
const playdl = require('play-dl'); const playdl = require('play-dl');
const ConsolerLogger = require('../utils/logger');
const logger = new ConsolerLogger();
async function getStream(query) { async function getStream(query) {
try { try {
@@ -35,7 +38,15 @@ async function getStream(query) {
: await playdl.video_info( : await playdl.video_info(
`https://www.youtube.com/watch?v=${videoId}`, `https://www.youtube.com/watch?v=${videoId}`,
); );
console.log('\x1b[36m', ' Id: ', videoId, 'Alternative search:', usingYtsr);
logger.info('Search request', { file: 'Youtube.JS',
Id: videoId,
alternativeSearch: usingYtsr,
length: usingYtsr
? infoResult.items[0].duration
: infoResult.video_details.durationInSec / 60,
SearchQuery: query });
return { return {
title: title:
(usingYtsr (usingYtsr
@@ -52,7 +63,7 @@ async function getStream(query) {
userInput: query, userInput: query,
}; };
} catch (error) { } catch (error) {
console.log('\x1b[31m', error); logger.error(error);
return null; return null;
} }
} }

View File

@@ -6,7 +6,10 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js", "start": "node index.js",
"lint": "eslint --fix --ext .js,.jsx ." "lint": "eslint --fix --ext .js,.jsx .",
"start-server": "pm2 start index.js",
"stop-server": "pm2 stop index.js",
"updater": "node maintenance.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -29,6 +32,8 @@
"discord.js": "^14.11.0", "discord.js": "^14.11.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"ffmpeg-static": "^4.2.7", "ffmpeg-static": "^4.2.7",
"lodash": "^4.17.21",
"node-schedule": "^2.1.1",
"opusscript": "^0.1.0", "opusscript": "^0.1.0",
"play-dl": "^1.9.6", "play-dl": "^1.9.6",
"soundcloud-scraper": "^5.0.3", "soundcloud-scraper": "^5.0.3",

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-console */
const play = require('play-dl'); const play = require('play-dl');
async function ReAuth() { async function ReAuth() {
@@ -8,10 +9,10 @@ async function ReAuth() {
}, },
}); });
console.log(`Soudncloud Client ID: ${clientID}`); console.log(`Soundcloud Client ID: ${clientID}`);
}); });
play.authorization(); play.authorization();
} }
module.exports.ReAuth = ReAuth; module.exports.ReAuth = ReAuth;

View File

@@ -14,7 +14,8 @@ async function getMusicStream(query) {
stream = await spotify.getStream(query); stream = await spotify.getStream(query);
songTitle = stream.title; songTitle = stream.title;
songDuration = stream.duration; songDuration = stream.duration;
stream = stream.stream; stream = stream?.stream;
type = StreamType.Opus;
} else if (query.includes('soundcloud.com')) { } else if (query.includes('soundcloud.com')) {
stream = await soundcloud.getStream(query); stream = await soundcloud.getStream(query);
songTitle = stream.title; songTitle = stream.title;

57
utils/logger.js Normal file
View File

@@ -0,0 +1,57 @@
/* eslint-disable no-console */
function loggerDate() {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hours = date.getHours();
const minutes = date.getMinutes();
const seconds = date.getSeconds();
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
class ConsolerLogger {
constructor() {
this.colors = {
info: '\x1b[36m%s\x1b[0m',
success: '\x1b[32m%s\x1b[0m',
warning: '\x1b[33m%s\x1b[0m',
error: '\x1b[31m%s\x1b[0m',
register: '\x1b[35m',
add: '\x1b[36m',
log: '\x1b[37m',
};
}
info(...messages) {
console.log(this.colors.info, loggerDate(), ...messages);
}
success(...messages) {
console.log(this.colors.success, loggerDate(), ...messages);
}
warning(...messages) {
console.log(this.colors.warning, loggerDate(), ...messages);
}
error(...messages) {
console.log(this.colors.error, loggerDate(), ...messages);
}
register(...messages) {
console.log(this.colors.register, loggerDate(), ...messages);
}
add(...messages) {
console.log(this.colors.add, loggerDate(), ...messages);
}
log(...messages) {
console.log(this.colors.log, loggerDate(), ...messages);
}
}
module.exports = ConsolerLogger;

View File

@@ -10,80 +10,23 @@ const process = require('dotenv').config();
const { clientId } = process.parsed; const { clientId } = process.parsed;
const { EmbedBuilder } = require('discord.js');
const musicQueue = require('../musicQueue'); const musicQueue = require('../musicQueue');
const { progressBar } = require('./progress'); const { nowPlayingMessage, intervalMap, currentInteractionIds } = require('./nowPlayingMessage');
const ConsolerLogger = require('./logger');
const currentInteractionIds = new Map();
const currentInteractions = new Map();
const oldConnections = []; const oldConnections = [];
const timeoutTimer = new Map(); const timeoutTimer = new Map();
const logger = new ConsolerLogger();
// TODO FIX THIS SHIT!!! ISSUES WITH DISPLAYING NAME AND STATUS WHEN UPDATING
function nowPLayingMessage(interaction, song, oldInteractionId) {
progressBar(0, 0, true);
if (interaction.commandName === 'play') {
interaction.followUp('~🎵~').then((message) => {
const songTitle = song.title;
// const embed = new EmbedBuilder()
// .setColor('#E0B0FF')
// .setTitle(`Now playing: ${songTitle}`)
// .setDescription(
// progressBar(song.duration, 10).progressBarString,
// );
const embed = new EmbedBuilder()
.setColor('#E0B0FF')
.setTitle(`Now playing: ${songTitle}`);
message.edit({
embeds: [embed],
});
const inter = setInterval(async () => {
const { progressBarString, isDone } = progressBar(
song.duration,
10,
);
if (isDone || message.id !== oldInteractionId) {
// clearInterval(inter);
return;
}
if (message.id != null && interaction.guild.id !== oldInteractionId) {
interaction.channel.messages.fetch().then(async (channel) => {
const filter = channel.filter((msg) => msg.author.id === clientId);
const latestMessage = await interaction.channel.messages.fetch(filter.first().id);
latestMessage.edit({
embeds: [embed.setTitle(`Now playing: ${songTitle}`)],
});
});
}
}, 2000);
currentInteractionIds.set(interaction.guild.id, interaction);
currentInteractions.set(interaction.guild.id, interaction.id);
});
}
}
async function musicPlayer(guildId, connection, interaction) { async function musicPlayer(guildId, connection, interaction) {
try { try {
const oldInteractions = await currentInteractions.get(interaction.guild.id);
const oldInteractionId = await currentInteractionIds.get(interaction.guild.id); const oldInteractionId = await currentInteractionIds.get(interaction.guild.id);
const serverQueue = musicQueue.getQueue(guildId); const serverQueue = musicQueue.getQueue(guildId);
const oldConnection = oldConnections const oldConnection = oldConnections
.find((guidConnection) => guidConnection[0] === interaction.guild.id); .find((guidConnection) => guidConnection[0] === interaction.guild.id);
if (serverQueue.length === 0) {
oldConnection[1].destroy();
}
const song = serverQueue[0]; const song = serverQueue[0];
if (song.stream === undefined) { if (!song || song.stream === undefined) {
musicQueue.removeFromQueue(guildId);
musicPlayer(guildId, connection);
return; return;
} }
@@ -97,30 +40,44 @@ async function musicPlayer(guildId, connection, interaction) {
}, },
}); });
player.play(resource); if (!resource.ended) {
player.play(resource);
} else {
logger.warning('Song ended prematurely.', song.title);
}
connection.subscribe(player); connection.subscribe(player);
nowPLayingMessage(interaction, song, oldInteractions); nowPlayingMessage(interaction, song);
oldConnections.push([interaction.guild.id, connection]); oldConnections.push([interaction.guild.id, connection]);
// Add an event listener for the Idle event of the audio player
player.on(AudioPlayerStatus.Idle, async () => { player.on(AudioPlayerStatus.Idle, async () => {
console.log('Song ended:', song.title); logger.info(`Song ended: ${song.title}`, 'Started by:', interaction.user.username);
if (serverQueue.length !== 1) { // Check if the audio resource has ended
await musicQueue.removeFromQueue(guildId); if (resource.ended) {
musicPlayer(guildId, connection, interaction); // If the audio resource has ended, play the next song
}
// timeoutTimer.set(guildId, setTimeout(async () => { if (serverQueue.length !== 0) {
// await musicQueue.removeFromQueue(guildId); await musicQueue.removeFromQueue(guildId);
// connection.destroy(); musicPlayer(guildId, connection, interaction);
// }, 10000)); logger.info(`Playing next song...${serverQueue}`);
} else {
// If there are no more songs in the queue, destroy the connection
connection.destroy();
logger.info('Connection destroyed.');
// Clear the interval for updating the progress bar
const interval = intervalMap.get(interaction.guild.id);
clearInterval(interval);
}
}
}); });
player.on(AudioPlayerStatus.Playing, () => { player.on(AudioPlayerStatus.Playing, () => {
console.log('pausing timer'); logger.info(`Playing: ${song.title}, Started by: ${interaction.user.username}`);
clearTimeout( clearTimeout(
logger.info('Previous song timer cleared.'),
timeoutTimer.get(guildId), timeoutTimer.get(guildId),
); );
}); });
@@ -130,13 +87,15 @@ async function musicPlayer(guildId, connection, interaction) {
const { lastMessage } = oldInteractionId.channel; const { lastMessage } = oldInteractionId.channel;
const filter = channel.filter((message) => message.author.id === clientId && message.id !== lastMessage.id); const filter = channel.filter((message) => message.author.id === clientId && message.id !== lastMessage.id);
setTimeout(() => { setTimeout(() => {
oldInteractionId.channel.bulkDelete(filter); logger.info('Removing old messages...');
oldInteractionId.channel.bulkDelete(filter)
.catch((error) => logger.error(error));
}, 1000); }, 1000);
}); });
} }
} catch (error) { } catch (error) {
console.error(error); logger.error(error);
interaction.followUp('There was an error playing the song.'); interaction.followUp('There was an error playing the song.', { ephemeral: true });
} }
} }

View File

@@ -0,0 +1,68 @@
const process = require('dotenv').config();
const { clientId } = process.parsed;
const { EmbedBuilder } = require('discord.js');
const { progressBar } = require('./progress');
const currentInteractionIds = new Map();
const currentInteractions = new Map();
const messageTimerMap = new Map();
const intervalMap = new Map(); // Add a new map to keep track of interval IDs
function nowPlayingMessage(interaction, song, prematureEnd = false) {
const timeoutIDs = messageTimerMap.get(interaction.guild.id);
if (timeoutIDs) {
timeoutIDs.forEach((timeoutID) => clearTimeout(timeoutID));
}
if (interaction.commandName === 'play') {
interaction.followUp('~🎵~').then((message) => {
const songTitle = song.title;
const embed = new EmbedBuilder()
.setColor('#E0B0FF')
.setTitle(`Now playing: ${songTitle}`)
.setDescription(
progressBar(song.duration, 10).progressBarString,
);
message.edit({
embeds: [embed],
});
const inter = setInterval(async () => {
const messageString = progressBar(
song.duration,
10,
);
if (message.id != null) {
interaction.channel.messages.fetch().then(async (channel) => {
const filter = channel.filter((msg) => msg.author.id === clientId);
const latestMessage = await interaction.channel.messages.fetch(filter.first().id);
latestMessage.edit({
embeds: [embed.setDescription(messageString.progressBarString)],
});
});
}
}, 5000);
// Store the interval ID in the intervalMap
intervalMap.set(interaction.guild.id, inter);
// Store the timeoutID in an array associated with the key
if (!messageTimerMap.has(interaction.guild.id) || !prematureEnd) {
messageTimerMap.set(interaction.guild.id, []);
}
messageTimerMap.get(interaction.guild.id).push(inter);
progressBar(0, 0, true);
currentInteractionIds.set(interaction.guild.id, interaction);
currentInteractions.set(interaction.guild.id, interaction.id);
});
}
}
module.exports.nowPlayingMessage = nowPlayingMessage;
module.exports.intervalMap = intervalMap;
module.exports.currentInteractionIds = currentInteractionIds;

View File

@@ -30,8 +30,9 @@ const progressBar = (totalInMilliseconds, size, reset = false) => {
totalTimeText = totalTimeText.slice(3); totalTimeText = totalTimeText.slice(3);
} }
const progressBarString = `${elapsedTimeText} \`\`\`${progressText}${emptyProgressText}\`\`\` ${totalTimeText}`; // Creating and returning the bar const progressBarString = `${elapsedTimeText} \`${progressText}${emptyProgressText}\` ${totalTimeText}`; // Creating and returning the bar
return { progressBarString, isDone: percentage === 1 }; return { progressBarString, isDone: percentage === 1 };
}; };
module.exports.progressBar = progressBar; module.exports.progressBar = progressBar;

View File

@@ -1,6 +1,9 @@
const { SlashCommandBuilder } = require('@discordjs/builders'); const { SlashCommandBuilder } = require('@discordjs/builders');
const { REST } = require('@discordjs/rest'); const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9'); const { Routes } = require('discord-api-types/v9');
const ConsolerLogger = require('./logger');
const logger = new ConsolerLogger();
async function registerCommands(clientId, token) { async function registerCommands(clientId, token) {
const commands = [ const commands = [
@@ -32,6 +35,15 @@ async function registerCommands(clientId, token) {
new SlashCommandBuilder() new SlashCommandBuilder()
.setName('stop') .setName('stop')
.setDescription('Stops the current song!'), .setDescription('Stops the current song!'),
new SlashCommandBuilder()
.setName('skip')
.setDescription('Skips the current song!'),
new SlashCommandBuilder()
.setName('leave')
.setDescription('Leaves the voice channel!'),
new SlashCommandBuilder()
.setName('previous')
.setDescription('Plays the previous song!'),
]; ];
const rest = new REST({ const rest = new REST({
@@ -40,15 +52,15 @@ async function registerCommands(clientId, token) {
.setToken(token); .setToken(token);
try { try {
console.log('\x1b[35m', 'Started refreshing application (/) commands.'); logger.register('Started refreshing application (/) commands.');
await rest.put(Routes.applicationCommands(clientId), { await rest.put(Routes.applicationCommands(clientId), {
body: commands, body: commands,
}); });
console.log('\x1b[35m', 'Successfully reloaded application (/) commands.'); logger.register('Successfully reloaded application (/) commands.');
} catch (error) { } catch (error) {
console.error(error); logger.error('Failed to reload application (/) commands.');
} }
} }

8
utils/setStatus.js Normal file
View File

@@ -0,0 +1,8 @@
const { botClient } = require('../index');
async function setStatus(status) {
await botClient.user.setActivity(status);
}
module.exports.setStatus = setStatus;
module.exports.setStatus = setStatus;