From d02dd5baceb479a9be75f16ce45437a0475d620d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zachary=20Gu=C3=A9not?= Date: Sun, 28 May 2023 20:39:11 +0200 Subject: [PATCH] =?UTF-8?q?Relance=20music=20si=20crash/reboot=20+=20R?= =?UTF-8?q?=C3=A9=C3=A9criture=20/amp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commands/global/amp.js | 144 +++++++++++------- commands/global/crack.js | 4 +- commands/music/play.js | 6 + commands/music/player.js | 4 +- commands/music/stop.js | 6 + events/interactionCreate.js | 6 +- events/ready.js | 58 ++++++- eventsPlayer/disconnect.js | 5 + utilsAMP/ADSModule/GetInstances.js | 14 ++ .../ManageInstance.js} | 11 +- .../RestartInstance.js} | 9 +- utilsAMP/CheckSession.js | 13 ++ utilsAMP/Core/Login.js | 23 +++ utilsAMP/getInstances.js | 17 --- utilsAMP/login.js | 22 --- 15 files changed, 234 insertions(+), 108 deletions(-) create mode 100644 utilsAMP/ADSModule/GetInstances.js rename utilsAMP/{manageInstance.js => ADSModule/ManageInstance.js} (78%) rename utilsAMP/{restartInstance.js => ADSModule/RestartInstance.js} (60%) create mode 100644 utilsAMP/CheckSession.js create mode 100644 utilsAMP/Core/Login.js delete mode 100644 utilsAMP/getInstances.js delete mode 100644 utilsAMP/login.js diff --git a/commands/global/amp.js b/commands/global/amp.js index 048dfa9..0a8387f 100644 --- a/commands/global/amp.js +++ b/commands/global/amp.js @@ -1,82 +1,124 @@ -const { SlashCommandBuilder, EmbedBuilder } = require('discord.js') -require('dotenv').config() -require('require-all')(__dirname + '/../../utilsAMP') +const { SlashCommandBuilder, EmbedBuilder, inlineCode } = require('discord.js') +let dotenv = require('dotenv') +dotenv.config() + +const appDir = require('path').dirname(require.main.filename) +const API = require('require-all')(appDir + '/utilsAMP') + +function failMsg(data) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` } +function errorMsg(data) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` } module.exports = { data: new SlashCommandBuilder().setName('amp').setDescription('Accède à mon panel de jeu AMP !') - //.addSubcommand(subcommand => subcommand.setName('api_info').setDescription('Prints info about the API.')) .addSubcommand(subcommand => subcommand.setName('login').setDescription("Connectez-vous avant d'effectuer une autre commande !") .addStringOption(option => option.setName('username').setDescription("Nom d'Utilisateur").setRequired(true)) .addStringOption(option => option.setName('password').setDescription('Mot de Passe').setRequired(true)) .addBooleanOption(option => option.setName('remember').setDescription('Mémoriser les identifiants').setRequired(true)) .addStringOption(option => option.setName('otp').setDescription('Code de double authentification'))) + .addSubcommandGroup(subcommandgroup => subcommandgroup.setName('instances').setDescription('Intéragir avec les instances AMP.') + .addSubcommand(subcommand => subcommand.setName('list').setDescription('Liste toutes les instances disponibles.')) + .addSubcommand(subcommand => subcommand.setName('manage').setDescription('Gérer une instance.') .addStringOption(option => option.setName('name').setDescription("Nom de l'instance").setRequired(true))) - .addSubcommand(subcommand => subcommand.setName('list').setDescription('Liste toutes les instances disponibles.')) + .addSubcommand(subcommand => subcommand.setName('restart').setDescription('Redémarre une instance.') .addStringOption(option => option.setName('name').setDescription("Nom de l'instance").setRequired(true)))), async execute(interaction) { - const base_url = process.env.AMP_HOST + '/API' - + // Let the user login if (interaction.options.getSubcommand() == 'login') { + // Get a SessionID and a RememberMeToken if wanted await interaction.deferReply({ ephemeral: true }) - let result = await login(base_url, interaction.options) - if (result.status === 'success') return await interaction.editReply(`You are successfully logged in as **${result.data.userInfo.Username}** !`) - else if (result.status === 'fail') return await interaction.editReply(`Sorry, something bad happened ! (${result.data.Message})`) - else if (result.status === 'error') return await interaction.editReply(`Sorry, there has been an error ! (${result.data.error_code})`) - } - else if (interaction.options.getSubcommandGroup() == 'instances') { - if (interaction.options.getSubcommand() == 'list') { - await interaction.deferReply() + let details = { + username: interaction.options.getString('username'), + password: interaction.options.getString('password'), + token: interaction.options.getString('otp') || '', + rememberMe: interaction.options.getBoolean('remember') + } - let result = await getInstances(base_url) - if (result.status === 'success') { - let fields = [] - result.instances.forEach(instance => { - fields.push({ - name: instance.FriendlyName, - value: `**ID:** ${instance.InstanceID} - **Running:** ${instance.Running} - **IP:** ${instance.IP} - **Port:** ${instance.Port} - **Module:** ${instance.Module}`, - inline: true - }) - }) - let embed = new EmbedBuilder() - .setTitle('Instances') - .setDescription('Liste de toutes les instances disponibles.') - .setColor(interaction.guild.members.me.displayColor) - .setTimestamp() - .setFields(fields) - return await interaction.followUp({ embeds: [embed] }) + let result = await API.Core.Login(details) + if (result.status === 'success') return await interaction.followUp(`Tu es connecté au panel sous **${result.data.userInfo.Username}** !`) + else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) + else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) + } + await interaction.deferReply() + + // Check if the SessionID is still valid + let sessionID = dotenv.config().parsed.AMP_SESSIONID + + let session = await API.CheckSession(sessionID) + if (session.status === 'fail') { + console.log(session) + if (process.env.AMP_REMEMBER_TOKEN) { + // Refresh the SessionID if the RememberMeToken is available + let details = { + username: process.env.AMP_USERNAME, + password: '', + token: process.env.AMP_REMEMBER_TOKEN, + rememberMe: true } + let result = await API.Core.Login(details) + console.log(result) + if (result.status === 'success') sessionID = result.data.sessionID + else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) + else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) + } + else { + // If no RememberMeToken is available, ask to login + return await interaction.followUp(`Tu dois te connecter avant d'effectuer une autre commande !`) + } + } + else if (session.status === 'error') return await interaction.followUp(errorMsg(session.data)) + + if (interaction.options.getSubcommandGroup() == 'instances') { + if (interaction.options.getSubcommand() == 'list') { + let result = await API.ADSModule.GetInstances(sessionID) + + if (result.status === 'success') { + await interaction.followUp({ content: `${result.data.result.length} hôtes trouvés !` }) + result.data.result.forEach(async host => { + let fields = [] + host.AvailableInstances.forEach(instance => { + fields.push({ + name: instance.FriendlyName, + value: `**ID:** ${instance.InstanceID} + **Running:** ${instance.Running} + **IP:** ${instance.IP} + **Port:** ${instance.Port} + **Module:** ${instance.Module}`, + inline: true + }) + }) + let embed = new EmbedBuilder() + .setTitle('Instances') + .setDescription(`Liste des instances de l'hôte **${host.FriendlyName}** :`) + .setColor(interaction.guild.members.me.displayColor) + .setTimestamp() + .setFields(fields) + return await interaction.channel.send({ embeds: [embed] }) + }) + } + else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) + else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) } else if (interaction.options.getSubcommand() == 'manage') { - await interaction.deferReply() - - let result = await manageInstance(base_url, interaction.options.getString('name')) + let query = interaction.options.getString('name') + let result = await API.ADSModule.ManageInstance(sessionID, query) + if (result.status === 'success') return await interaction.followUp(`Ok !`) + else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) + else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) } else if (interaction.options.getSubcommand() == 'restart') { - await interaction.deferReply() + let query = interaction.options.getString('name') + let result = await API.ADSModule.RestartInstance(sessionID, query) - let result = await restartInstance(base_url, interaction.options.getString('name')) if (result.status === 'success') return await interaction.followUp(`Ok !`) + else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) + else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) } - /*else if (interaction.options.getSubcommand() == 'api_info') { - await interaction.deferReply() - let url = `${base_url}/Core/GetAPISpec` - let headers = { headers: { SESSIONID: localStorage.getItem("AMP_sessionID") } } - try { - let response = await axios.post(url, headers) - console.log(response.data) - await interaction.editReply('Ok !') - } catch (error) { console.log(error), await interaction.editReply("HTTP Error !") } - }*/ } } } \ No newline at end of file diff --git a/commands/global/crack.js b/commands/global/crack.js index e3bf70a..6db8b8d 100644 --- a/commands/global/crack.js +++ b/commands/global/crack.js @@ -1,6 +1,8 @@ const { SlashCommandBuilder } = require('discord.js') const fs = require('fs') -require('require-all')(__dirname + '/../../utilsCrack') + +const appDir = require('path').dirname(require.main.filename) +require('require-all')(appDir + '/utilsCrack') var headers1 = { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", diff --git a/commands/music/play.js b/commands/music/play.js index 2d6122d..f69d377 100755 --- a/commands/music/play.js +++ b/commands/music/play.js @@ -70,6 +70,12 @@ module.exports = { await entry.getTask() queue.addTrack(track) + // Write the values in the .env file to recover the player if the bot restarts + writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', interaction.channel.id) + writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', voiceChannel.id) + writeEnv('DISCORD_MUSIC_CURRENT_TRACK', track.url) + writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', 0) + try { if (!queue.isPlaying()) await queue.node.play() track.source = track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu' diff --git a/commands/music/player.js b/commands/music/player.js index e8f61e8..47add8f 100755 --- a/commands/music/player.js +++ b/commands/music/player.js @@ -1,5 +1,7 @@ const { SlashCommandBuilder } = require('discord.js') -const generatePlayer = require('../../utilsPlayer/generate.js') + +const appDir = require('path').dirname(require.main.filename) +const generatePlayer = require(appDir + '/utilsPlayer/generate.js') module.exports = { data: new SlashCommandBuilder() diff --git a/commands/music/stop.js b/commands/music/stop.js index 48ca926..9a13649 100755 --- a/commands/music/stop.js +++ b/commands/music/stop.js @@ -8,6 +8,12 @@ module.exports = { async execute(interaction) { let queue = useQueue(interaction.guild.id) queue.delete() + + writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', '') + writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', '') + writeEnv('DISCORD_MUSIC_CURRENT_TRACK', '') + writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', '') + return await interaction.reply('Musique arrêtée !') } } \ No newline at end of file diff --git a/events/interactionCreate.js b/events/interactionCreate.js index 8864207..f82a6ec 100755 --- a/events/interactionCreate.js +++ b/events/interactionCreate.js @@ -1,6 +1,8 @@ const { Events } = require('discord.js') -const editPlayer = require('../utilsPlayer/edit.js') -const playerButtons = require('../utilsPlayer/buttons.js') + +const appDir = require('path').dirname(require.main.filename) +const editPlayer = require(appDir + '/utilsPlayer/edit.js') +const playerButtons = require(appDir + '/utilsPlayer/buttons.js') module.exports = { name: Events.InteractionCreate, diff --git a/events/ready.js b/events/ready.js index 213246f..ac5e550 100755 --- a/events/ready.js +++ b/events/ready.js @@ -1,9 +1,13 @@ const { Events } = require('discord.js') +const { useMasterPlayer, useQueue } = require('discord-player') +require('dotenv').config() + //const { DataTypes } = require("sequelize") //const sequelize = require('../utils/initSequelize.js') -const generatePlayer = require('../utilsPlayer/generate.js') -const getUptime = require('../utils/getUptime.js') -require('dotenv').config() + +const appDir = require('path').dirname(require.main.filename) +const generatePlayer = require(appDir + '/utilsPlayer/generate.js') +const getUptime = require(appDir + '/utils/getUptime.js') const dance = async function (bot_id, channel, embed, components) { let messages = await channel.messages.fetch() @@ -17,9 +21,50 @@ const dance = async function (bot_id, channel, embed, components) { module.exports = { name: Events.ClientReady, once: true, - execute(client) { + async execute(client) { console.log(`\u001b[1;35m Ready! Logged in as ${client.user.tag}`) + // Check if a music session was active before the bot was restarted + if (process.env.DISCORD_MUSIC_CURRENT_TRACK) { + let textChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_TEXTCHANNEL_ID) + let voiceChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_VOICECHANNEL_ID) + + let player = useMasterPlayer() + let queue = player.nodes.create(textChannel.guild, { + metadata: { + channel: voiceChannel, + client: textChannel.guild.members.me, + requestedBy: client.user + }, + selfDeaf: true, + volume: 20, + leaveOnEmpty: true, + leaveOnEmptyCooldown: 300000, + leaveOnEnd: true, + leaveOnEndCooldown: 300000, + skipOnNoStream: true + }) + + try { if (!queue.connection) await queue.connect(voiceChannel) } + catch (error) { console.error(error); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) } + + let result = await player.search(process.env.DISCORD_MUSIC_CURRENT_TRACK, { requestedBy: client.user }) + if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${query}** !`) + let track = result.tracks[0] + + let entry = queue.tasksQueue.acquire() + await entry.getTask() + queue.addTrack(track) + + try { + await queue.node.play() + queue.node.seek(process.env.DISCORD_MUSIC_CURRENT_PROGRESS) + queue.setRepeatMode(1) + await textChannel.send(`Relancement de la musique suite à mon redémarrage...`) + } catch (error) { console.error(error); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) } + finally { queue.tasksQueue.release() } + } + //try { // sequelize.authenticate() // console.log('Connection has been established successfully.') @@ -45,8 +90,11 @@ module.exports = { return console.log(`\u001b[1;31m Error: Aucun channel trouvé avec l'id \`${process.env.DISCORD_PLAYERCHANNEL_ID}\`, veuillez utiliser la commande \`/setchannel\` !`) } - let { embed, components } = await generatePlayer(guild) + // Keep track of the music progress if the bot reboots + let queue = useQueue(guild.id) + if (queue) if (queue.isPlaying()) writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', queue.node.playbackTime) + let { embed, components } = await generatePlayer(guild) if (components) { embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)} / ${embed.data.footer.text}` }) await dance(client.user.id, channel, embed, components) diff --git a/eventsPlayer/disconnect.js b/eventsPlayer/disconnect.js index 136df98..2575e76 100644 --- a/eventsPlayer/disconnect.js +++ b/eventsPlayer/disconnect.js @@ -3,5 +3,10 @@ module.exports = { async execute(queue, track) { // Emitted when the bot leaves the voice channel queue.metadata.channel.send("J'ai quitté le vocal !") + + writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', '') + writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', '') + writeEnv('DISCORD_MUSIC_CURRENT_TRACK', '') + writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', '') } } \ No newline at end of file diff --git a/utilsAMP/ADSModule/GetInstances.js b/utilsAMP/ADSModule/GetInstances.js new file mode 100644 index 0000000..9e50486 --- /dev/null +++ b/utilsAMP/ADSModule/GetInstances.js @@ -0,0 +1,14 @@ +const axios = require('axios') + +module.exports = (async (SESSIONID) => { + return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, { + SESSIONID + }).then(response => { + console.log(response.data) + if (!response.data.result) return { status: 'fail', data: response.data } + return { status: 'success', data: response.data } + }).catch(error => { + console.error(error) + return { status: 'error', data: error } + }) +}) \ No newline at end of file diff --git a/utilsAMP/manageInstance.js b/utilsAMP/ADSModule/ManageInstance.js similarity index 78% rename from utilsAMP/manageInstance.js rename to utilsAMP/ADSModule/ManageInstance.js index 58d799d..3937389 100644 --- a/utilsAMP/manageInstance.js +++ b/utilsAMP/ADSModule/ManageInstance.js @@ -1,9 +1,10 @@ const axios = require('axios') -require('dotenv').config() -module.exports = manageInstance = (async (url, FriendlyName) => { - let result = await axios.post(`${url}/ADSModule/GetInstances`, { - SESSIONID: process.env.AMP_SESSIONID +module.exports = (async (SESSIONID, FriendlyName) => { + require('dotenv').config() + + return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, { + SESSIONID }).then(response => { console.log(response.data) @@ -19,7 +20,7 @@ module.exports = manageInstance = (async (url, FriendlyName) => { }) if (result.status === 'success') return await axios.post(`${url}/ADSModule/ManageInstance`, { - SESSIONID: process.env.AMP_SESSIONID, + SESSIONID, InstanceId: result.data.instance_id }).then(response => { console.log(response.data) diff --git a/utilsAMP/restartInstance.js b/utilsAMP/ADSModule/RestartInstance.js similarity index 60% rename from utilsAMP/restartInstance.js rename to utilsAMP/ADSModule/RestartInstance.js index cc0a037..8c525fd 100644 --- a/utilsAMP/restartInstance.js +++ b/utilsAMP/ADSModule/RestartInstance.js @@ -1,9 +1,10 @@ const axios = require('axios') -require('dotenv').config() -module.exports = restartInstance = (async (url, InstanceName) => { - return await axios.post(`${url}/ADSModule/RestartInstance`, { - SESSIONID: process.env.AMP_SESSIONID, +module.exports = (async (SESSIONID, InstanceName) => { + require('dotenv').config() + + return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, { + SESSIONID, InstanceName }).then(response => { console.log(response.data) diff --git a/utilsAMP/CheckSession.js b/utilsAMP/CheckSession.js new file mode 100644 index 0000000..d735c43 --- /dev/null +++ b/utilsAMP/CheckSession.js @@ -0,0 +1,13 @@ +const axios = require('axios') + +module.exports = (async (SESSIONID) => { + return await axios.post(`${process.env.AMP_HOST}/API/ADSModule/GetInstances`, { + SESSIONID + }).then(response => { + if (!response.data.result) return { status: 'fail', data: response.data } + return { status: 'success', data: response.data } + }).catch(error => { + console.error(error) + return { status: 'error', data: error } + }) +}) \ No newline at end of file diff --git a/utilsAMP/Core/Login.js b/utilsAMP/Core/Login.js new file mode 100644 index 0000000..8fb1a11 --- /dev/null +++ b/utilsAMP/Core/Login.js @@ -0,0 +1,23 @@ +const axios = require('axios') + +const appDir = require('path').dirname(require.main.filename) +const writeEnv = require(appDir + '/utils/writeEnv') + +module.exports = (async (details) => { + require('dotenv').config() + console.log(details) + return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, + details + ).then(response => { + if (!response.data.success) return { status: 'fail', data: response.data } + + writeEnv('AMP_USERNAME', response.data.userInfo.Username) + writeEnv('AMP_SESSIONID', response.data.sessionID) + writeEnv('AMP_REMEMBER_TOKEN', response.data.rememberMeToken) + + return { status: 'success', data: response.data } + }).catch(error => { + console.error(error) + return { status: 'error', data: error } + }) +}) \ No newline at end of file diff --git a/utilsAMP/getInstances.js b/utilsAMP/getInstances.js deleted file mode 100644 index 1911958..0000000 --- a/utilsAMP/getInstances.js +++ /dev/null @@ -1,17 +0,0 @@ -const axios = require('axios') -require('dotenv').config() - -module.exports = getInstances = (async (url) => { - return await axios.post(`${url}/ADSModule/GetInstances`, { - SESSIONID: process.env.AMP_SESSIONID - }).then(response => { - console.log(response.data) - console.log(response.data.result[0].AvailableInstances) - - //if (!response.data.success) return { status: 'fail', data: response.data } - return { status: 'success', data: response.data, instances: response.data.result[0].AvailableInstances } - }).catch(error => { - console.error(error) - return { status: 'error', data: error } - }) -}) \ No newline at end of file diff --git a/utilsAMP/login.js b/utilsAMP/login.js deleted file mode 100644 index 80f666e..0000000 --- a/utilsAMP/login.js +++ /dev/null @@ -1,22 +0,0 @@ -const axios = require('axios') -const writeEnv = require('../utils/writeEnv') - -module.exports = login = (async (url, options) => { - return await axios.post(`${url}/Core/Login`, { - username: options.getString('username'), - password: options.getString('password'), - token: options.getString('otp') || '', - rememberMe: options.getBoolean('remember') - }).then(response => { - console.log(response.data) - if (!response.data.success) return { status: 'fail', data: response.data } - - writeEnv('AMP_SESSIONID', response.data.sessionID) - if (options.getBoolean('remember')) writeEnv('AMP_REMEMBER_TOKEN', response.data.rememberMeToken) - - return { status: 'success', data: response.data } - }).catch(error => { - console.error(error) - return { status: 'error', data: error } - }) -}) \ No newline at end of file