Version 1.0.2 - STABLE - Backend complété et prêt à l'usage

This commit is contained in:
2025-05-05 19:48:47 +02:00
parent 3aa4201dd2
commit e686edb0e6
23 changed files with 317 additions and 170 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "chopin-backend",
"version": "1.0.1",
"version": "1.0.2",
"description": "Discord Bot for music - Fetching everywhere !",
"main": "src/main.js",
"nodemonConfig": {

View File

@@ -10,7 +10,7 @@ const command = new Command("about", "Affiche des informations sur le bot", (cli
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = Math.floor(uptime % 60);
const embed = new Embed()
const embed = new Embed(interaction)
embed.setColor(237, 12, 91)
embed.setThumbnail("https://cdn.discordapp.com/avatars/" + client.user.id + "/" + client.user.avatar + ".png")
embed.setTitle('Subsonics - Chopin')
@@ -31,7 +31,7 @@ const command = new Command("about", "Affiche des informations sur le bot", (cli
embed.addField('Ytdl', packageJson.dependencies["@distube/ytdl-core"].replace("^", ""),true)
embed.addColumn()
embed.send(interaction)
embed.send()
})

View File

@@ -3,7 +3,7 @@ const { Embed } = require('../Embed');
const command = new Command("help", "Affiche la liste des commandes", (client, interaction) => {
const embed = new Embed()
const embed = new Embed(interaction)
embed.setColor(0x03ff2d)
embed.setTitle('Comment assister au concert ?')
embed.setDescription("**Eh ! Tu as eu ton ticket ? Tant mieux ! Voici la liste des commandes à utiliser dans le salon prévu à cet effet !**")
@@ -28,7 +28,7 @@ const command = new Command("help", "Affiche la liste des commandes", (client, i
})
embed.addField("La queue et la gestion du redémarrage se fait par le site https://subsonics.raphix.fr/", ":star:" )
embed.setThumbnail("https://static.wikia.nocookie.net/codelyoko/images/9/95/Subdigitals.jpg/revision/latest/scale-to-width-down/180?cb=20120105180510&path-prefix=fr");
embed.send(interaction)
embed.send()
})
module.exports = {command}

View File

@@ -3,7 +3,7 @@ const {Embed, EmbedError} = require("../Embed")
const {Button} = require("../Button")
const command = new Command("invite", "Invite moi sur d'autres serveurs", (client, interaction) => {
const embed = new Embed()
const embed = new Embed(interaction)
embed.setColor(0xFF007F)
embed.setTitle('**Inviter le bot sur d\'autres serveurs**')
embed.setDescription('Vous pouvez m\'inviter sur d\'autres serveurs en cliquant sur le bouton ci-dessous.')
@@ -13,7 +13,7 @@ const command = new Command("invite", "Invite moi sur d'autres serveurs", (clien
const linkButton = new Button("Invite", null, 5, "https://discord.com/oauth2/authorize?client_id=" + client.user.id + "&scope=bot+applications.commands&permissions=8")
embed.addButton(linkButton)
embed.send(interaction)
embed.send()
})

View File

@@ -4,11 +4,15 @@ const {Player, AllPlayers} = require("../../player/Player")
const command = new Command("leave", "Quitter le salon vocal", (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour arrêter le bot !").send(interaction)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour arrêter le bot !", interaction)
const channel = interaction.member.voice.channel
var embed = new Embed()
var embed = new Embed(interaction)
if(AllPlayers.has(channel.guildId)) {
const player = AllPlayers.get(channel.guildId)
if(!player?.connected) {
return embed.returnError("Le bot n'est pas connecté à ce salon vocal")
}
player.leave()
@@ -16,12 +20,14 @@ const command = new Command("leave", "Quitter le salon vocal", (client, interact
embed.setTitle('**Déconnexion**')
embed.setDescription('Déconnexion du salon vocal')
embed.setThumbnail("https://www.iconsdb.com/icons/download/white/phone-51-64.png")
embed.send()
} else {
embed = new EmbedError("Le bot n'est pas connecté à ce salon vocal")
embed.returnError("Le bot n'est pas connecté à ce salon vocal")
}
embed.send(interaction)
})

View File

@@ -5,13 +5,16 @@ const { Song } = require('../../player/Song');
const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal", async (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer un média !").send(interaction, true)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer un média !", interaction, true)
const media = interaction.options.get("media")
const now = interaction.options.getBoolean("now") || false
if(media.attachment.contentType != "audio/mpeg" && media.attachment.contentType != "audio/wav") return new EmbedError("Le média doit être un fichier audio MP3 ou WAV !").send(interaction)
if(media.attachment.contentType != "audio/mpeg" && media.attachment.contentType != "audio/wav") return new EmbedError("Le média doit être un fichier audio MP3 ou WAV !", interaction)
const embed = new Embed(interaction)
embed.setColor(0x15e6ed)
const channel = interaction.member.voice.channel
const song = new Song()
await song.processMedia(media, interaction.user.username)
@@ -19,8 +22,7 @@ const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal
const player = new Player(channel.guildId)
player.join(channel)
const embed = new Embed()
embed.setColor(0x15e6ed)
if(now) {
@@ -40,7 +42,7 @@ const command = new Command("media", "Lire un média MP3/WAV dans un salon vocal
embed.setThumbnail(song.thumbnail)
embed.send(interaction)
embed.send()
}, [{type: "FILE", name: "media", description: "Fichier audio à lire", required: true},

View File

@@ -5,20 +5,20 @@ const { Player } = require("../../player/Player")
const command = new Command("pause", "Mettre en pause / Reprendre la musique en cours", (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour mettre en pause la musique !").send(interaction)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour mettre en pause la musique !", interaction)
const channel = interaction.member.voice.channel
const player = new Player(channel.guildId)
const result = player.pause()
var embed = new Embed()
var embed = new Embed(interaction)
embed.setColor(0x03ff2d)
result.then((pause) => {
if(pause == "no_music") {
embed = new EmbedError("Il n'y a pas de musique en cours de lecture")
embed.returnError("Il n'y a pas de musique en cours de lecture")
} else if(pause) {
embed.setTitle('Musique en pause')
@@ -32,7 +32,7 @@ const command = new Command("pause", "Mettre en pause / Reprendre la musique en
embed.setThumbnail("https://www.iconsdb.com/icons/download/white/play-64.png")
}
embed.send(interaction)
embed.send()
})
// Réponse en embed

View File

@@ -7,18 +7,19 @@ const spotify = require("../../media/SpotifyInformation");
const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer une musique !").send(interaction)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour jouer une musique !", interaction)
const url = interaction.options.get("url")
const channel = interaction.member.voice.channel
const now = interaction.options.getBoolean("now") || false
const embed = new Embed(interaction)
await Finder.search(url.value).then(async (song) => {
if(!song) return new EmbedError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés").send(interaction)
if(!song) return embed.returnError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés")
const player = new Player(channel.guildId)
player.join(channel)
const embed = new Embed()
embed.setColor(0x15e6ed)
// Check if song is playlist
@@ -56,7 +57,7 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
embed.setTitle("Ajoutée à la file d'attente")
}
embed.send(interaction)
embed.send()
if(song instanceof Playlist) {
if(song.type == "spotify") {

View File

@@ -4,9 +4,10 @@ const { Player, AllPlayers } = require("../../player/Player")
const command = new Command("previous", "Passe à la musique précédente", (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !").send(interaction)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !", interaction)
const channel = interaction.member.voice.channel
var embed = new Embed(interaction)
if(AllPlayers.has(channel.guildId)) {
@@ -14,34 +15,33 @@ const command = new Command("previous", "Passe à la musique précédente", (cli
const result = player.previous()
var embed = new Embed()
embed.setColor(0x15e6ed)
result.then((song) => {
if(song == "no_music") {
embed = new EmbedError("Il n'y a pas de musique précédemment jouée")
embed.returnError("Il n'y a pas de musique précédemment jouée")
} else if(song) {
// Result is a song
embed.setTitle('**Musique précédente !**')
embed.setDescription('**Titre : **' + song.title)
embed.addField('**Durée : **'+ song.readduration, "")
embed.addField("**Artiste : **" + song.author, "")
embed.setThumbnail(song.thumbnail)
embed.send()
}
embed.send(interaction)
})
} else {
return new EmbedError("Le bot n'est pas connecté").send(interaction)
return embed.returnError("Le bot n'est pas connecté", interaction)
}

View File

@@ -5,37 +5,38 @@ const { Player, AllPlayers } = require("../../player/Player")
const command = new Command("liste", "Affiche la file d'attente", (client, interaction) => {
const channel = interaction.member.voice.channel
var embed = new Embed(interaction)
if(AllPlayers.has(channel.guildId)) {
const player = new Player(channel.guildId)
const queue = player.queue.getNext()
var embed = new Embed()
embed.setColor(0x15e6ed)
if(queue.length == 0) {
embed = new EmbedError("Il n'y a pas de musique en file d'attente")
const player = new Player(channel.guildId)
const queue = player.queue.getNext()
} else if(queue.length > 0) {
if(queue.length == 0) {
embed.returnError("Il n'y a pas de musique en file d'attente")
// Result is a song
embed.setColor(0x15e6ed)
embed.setThumbnail("https://www.iconsdb.com/icons/download/white/list-2-64.png")
embed.setTitle('**File d\'attente :**')
embed.setDescription('**' + queue.length + ' musiques**')
queue.forEach((song, index) => {
// max 24 fields
if(index > 10) return
embed.addField(`**${index+1} - ${song.title}**`, `**Durée : **${song.readduration}\n**Artiste : **${song.author}`)
})
}
embed.send(interaction)
} else if(queue.length > 0) {
// Result is a song
embed.setColor(0x15e6ed)
embed.setThumbnail("https://www.iconsdb.com/icons/download/white/list-2-64.png")
embed.setTitle('**File d\'attente :**')
embed.setDescription('**' + queue.length + ' musiques**')
queue.forEach((song, index) => {
// max 24 fields
if(index > 10) return
embed.addField(`**${index+1} - ${song.title}**`, `**Durée : **${song.readduration}\n**Artiste : **${song.author}`)
})
embed.send()
}
} else {
return new EmbedError("Le bot n'est pas connecté").send(interaction)
embed.returnError("Le bot n'est pas connecté")
}
})

View File

@@ -5,7 +5,7 @@ const { Report } = require('../ReportSender');
const command = new Command("report", "Signaler un problème avec le bot", (client, interaction) => {
const report = new Report(interaction.user.username, interaction.options.getString("type"), interaction.options.getString("description"))
const result = report.send()
const embed = new Embed()
const embed = new Embed(interaction)
result.then((res) => {
@@ -20,7 +20,7 @@ const command = new Command("report", "Signaler un problème avec le bot", (clie
embed.setDescription("Votre rapport a bien été envoyé !")
}
embed.send(interaction)
embed.send()
})

View File

@@ -14,12 +14,12 @@ const command = new Command("restart", "Redémarre le bot", (client, interaction
}
const reason = interaction.options.getString("reason")
restart(reason)
const embed = new Embed()
const embed = new Embed(interaction)
embed.setColor(150, 20, 20)
embed.setTitle('Redémarrage')
embed.setDescription("Veuillez patientez, le bot va redémarrer dans un instant ! :arrows_counterclockwise:")
embed.addField('Raison', reason)
embed.send(interaction)
embed.send()
},
[{type: "STRING", name: "reason", description: "Raison du redémarrage", required: true}]
)

View File

@@ -4,22 +4,21 @@ const { Player, AllPlayers } = require("../../player/Player")
const command = new Command("skip", "Passe à la musique suivante", (client, interaction) => {
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !").send(interaction)
if(!interaction.member.voice.channel) return new EmbedError("Vous devez rejoindre un salon vocal pour passer à la musique suivante !", interaction)
const channel = interaction.member.voice.channel
var embed = new Embed(interaction)
if(AllPlayers.has(channel.guildId)) {
const player = new Player(channel.guildId)
const result = player.skip()
var embed = new Embed()
embed.setColor(0x15e6ed)
result.then((song) => {
if(song == "no_music") {
embed = new EmbedError("Il n'y a pas de musique en file d'attente")
embed.returnError("Il n'y a pas de musique en file d'attente", interaction)
} else if(song) {
@@ -35,11 +34,11 @@ const command = new Command("skip", "Passe à la musique suivante", (client, int
}
embed.send(interaction)
embed.send()
})
} else {
return new EmbedError("Le bot n'est pas connecté").send(interaction)
return embed.returnError("Le bot n'est pas connecté", interaction)
}

View File

@@ -8,14 +8,14 @@ const command = new Command("state", "Affiche la musique en cours", (client, int
const player = new Player(channel.guildId)
const song = player.queue.getCurrent()
var embed = new Embed()
embed.setColor(0x15e6ed)
if(!song) {
embed = new EmbedError("Il n'y a pas de musique en cours de lecture")
var embed = new EmbedError("Il n'y a pas de musique en cours de lecture", interaction)
} else if(song) {
var embed = new Embed(interaction)
// Result is a song
embed.setColor(0x15e6ed)
@@ -25,10 +25,10 @@ const command = new Command("state", "Affiche la musique en cours", (client, int
embed.addField("**Artiste : **", song.author)
embed.setThumbnail(song.thumbnail)
embed.send()
}
embed.send(interaction)
})
module.exports = {command}

View File

@@ -4,7 +4,7 @@ const { Embed } = require('../Embed');
const config = require('../../utils/Database/Configuration')
const command = new Command("web", "Affiche le lien vers le site web pour contrôler le bot", (client, interaction) => {
const embed = new Embed()
const embed = new Embed(interaction)
embed.setColor(0xffffff)
embed.setTitle('Subsonics - Chopin')
embed.addBotPicture(client)
@@ -13,7 +13,7 @@ const command = new Command("web", "Affiche le lien vers le site web pour contr
const linkButton = new Button("Site web", null, 5, config.getWebsiteLink())
embed.addButton(linkButton)
embed.send(interaction)
embed.send()
})

View File

@@ -3,10 +3,18 @@ const { EmbedBuilder, ActionRowBuilder } = require("discord.js");
class Embed {
fields;
buttons;
constructor() {
constructor (interaction, ephemeral) {
this.embed = new EmbedBuilder().setTimestamp()
this.fields = []
this.buttons = []
this.isSended = false
if(interaction) {
interaction.deferReply({ ephemeral: ephemeral }).then(() => {
this.isSended = true
})
this.interaction = interaction
this.ephemeral = ephemeral
}
}
setTitle(title) {
@@ -92,19 +100,32 @@ class Embed {
return this.embed
}
send(interaction, ephemeral) {
if(ephemeral === undefined) ephemeral = false;
interaction.reply({ embeds: [this.build()], ephemeral: ephemeral, components: this.buttons.length > 0 ? [this.actionRow] : [] })
async send() {
// Add a secutiry check to avoid sending an embed if the interaction is not defined and retry one again
while(!this.isSended) {
await new Promise(resolve => setTimeout(resolve, 50));
}
if(this.ephemeral === undefined) this.ephemeral = false;
this.interaction.editReply({ embeds: [this.build()], components: this.buttons.length > 0 ? [this.actionRow] : [] })
}
}
class EmbedError extends Embed {
constructor(message) {
super()
async returnError(message) {
this.setColor(150, 20, 20)
this.setTitle('Erreur')
this.setThumbnail("https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/Dialog-error-round.svg/2048px-Dialog-error-round.svg.png")
this.setDescription(message)
await this.send()
}
}
class EmbedError extends Embed {
constructor(message, interaction, ephemeral) {
super(interaction, ephemeral)
this.setColor(150, 20, 20)
this.setTitle('Erreur')
this.setThumbnail("https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/Dialog-error-round.svg/2048px-Dialog-error-round.svg.png")
this.setDescription(message)
this.send()
}
}

View File

@@ -76,7 +76,7 @@ async function search(query, multiple, forceType) {
return await soundcloud.getPlaylist(query)
}
// TODO: Add more providers
//MORELATER: Add more providers
}
module.exports = {search}

View File

@@ -204,6 +204,11 @@ class List {
}
moveNext(fromIndex, toIndex) {
// Check if fromIndex and toIndex are valid
if(fromIndex < 0 || fromIndex >= this.next.length + 1 || toIndex < 0 || toIndex >= this.next.length + 1) {
clog.error("Impossible de déplacer la musique, car l'index est invalide, GuildId : " + this.guildId)
return
}
if(fromIndex == toIndex) return;
const song = this.next[fromIndex]
this.next.splice(fromIndex, 1)

View File

@@ -1,6 +1,7 @@
const { joinVoiceChannel, getVoiceConnection, VoiceConnectionStatus, createAudioPlayer, AudioPlayerStatus, StreamType, createAudioResource } = require('@discordjs/voice');
const {List} = require('./List')
const {LogType} = require("loguix");
const songCheck = require('./SongCheck')
const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const { PassThrough } = require('stream');
@@ -91,6 +92,7 @@ class Player {
});
this.player.on(AudioPlayerStatus.Idle, () => {
if(this.checkConnection()) return
// Si la musique est en boucle, on relance la musique
if(this.loop) {
this.play(this.queue.current)
@@ -106,7 +108,7 @@ class Player {
});
this.player.on(AudioPlayerStatus.Playing, () => {
if(this.checkConnection()) return
plog.log(`GUILD : ${this.guildId} - Le player est en train de jouer le contenu suivant : ${this.queue.current.title}`);
Activity.setMusicActivity(this.queue.current.title, this.queue.current.author, this.queue.current.thumbnail)
process.emit("PLAYERS_UPDATE")
@@ -140,7 +142,8 @@ class Player {
duration: this.getDuration(),
playerState: playerStatus,
connectionState: connectionStatus,
channelId: this.channelId
channelId: this.channelId,
guildId: this.guildId,
}
return state
}
@@ -168,6 +171,7 @@ class Player {
}
async play(song) {
if(!songCheck.checkSong(song)) return
if(this.checkConnection()) return
if(this.queue.current != null) {
this.player.stop()
@@ -202,7 +206,7 @@ class Player {
}
async add(song) {
if(this.player.state.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) {
if(this.player?.state?.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) {
this.play(song)
return
}
@@ -212,15 +216,14 @@ class Player {
}
async readPlaylist(playlist, now) {
if(this.player.state.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) {
this.play(playlist.songs[0])
}
if(now) {
if(this.player?.state?.status == AudioPlayerStatus.Idle && this.queue.current === null && this.queue.next.length === 0) {
this.play(playlist.songs[0])
this.queue.addNextPlaylist(playlist, true)
} else {
this.queue.addNextPlaylist(playlist)
}
return
}
if(now) this.play(playlist.songs[0])
this.queue.addNextPlaylist(playlist, now)
plog.log(`GUILD : ${this.guildId} - La playlist a été ajoutée à la liste de lecture : ${playlist.title}`)
}
@@ -229,13 +232,15 @@ class Player {
if(this.player.state.status == AudioPlayerStatus.Paused) {
this.player.unpause()
plog.log(`GUILD : ${this.guildId} - La musique a été reprise`)
process.emit("PLAYERS_UPDATE")
return false
} else {
this.player.pause()
plog.log(`GUILD : ${this.guildId} - La musique a été mise en pause`)
process.emit("PLAYERS_UPDATE")
return true
}
process.emit("PLAYERS_UPDATE")
}
async leave() {
@@ -260,7 +265,7 @@ class Player {
}
async setDuration(duration) {
//FIXME: SET DURATION FONCTIONNE TRES LENTEMENT
if (this.checkConnection()) return;
if (this.queue.current == null) return;
if (this.currentResource == null) return;

View File

@@ -0,0 +1,44 @@
const {LogType} = require("loguix")
const {Song} = require("./Song")
const slog = new LogType("SongCheck")
function checkSong(song) {
if(!(song instanceof Song)) {
slog.error("La musique n'est pas une instance de la classe Song")
// Check if the song is valid and if it has all the required properties
if(song.title && song.id && song.author && song.url && song.duration && song.readduration && song.type) {
slog.log("Acceptation de la musique : " + song.title)
return true
} else {
slog.error("La musique n'est pas valide")
return false
}
}
if(!song.url) {
slog.error("La musique n'a pas d'url")
return false
}
if(!song.title) {
slog.error("La musique n'a pas de titre")
return false
}
if(!song.author) {
slog.error("La musique n'a pas d'auteur")
return false
}
if(!song.duration) {
slog.error("La musique n'a pas de durée")
return false
}
if(!song.readduration) {
slog.error("La musique n'a pas de durée lisible")
return false
}
if(!song.type) {
slog.error("La musique n'a pas de type")
return false
}
return true
}
module.exports = {checkSong}

View File

@@ -1,3 +1,5 @@
const { getReadableDuration } = require("../utils/TimeConverter");
class Playlist {
title = "Aucun titre";
id;
@@ -17,8 +19,11 @@ class Playlist {
this.authorId = authorId;
this.songs = songs || new Array();
this.thumbnail = thumbnail;
this.duration = duration;
this.readduration = readduration;
// Make the some of durations of the songs
if(this.songs.length > 0) {
this.duration = this.songs.reduce((acc, song) => acc + song.duration, 0);
this.readduration = getReadableDuration(this.duration);
}
this.description = description;
if(!this.url) {
this.type = "playlist";

View File

@@ -42,6 +42,7 @@ function init() {
for(var guild of discordBot.getGuilds().keys()) {
const player = players.getPlayer(guild)
if(player) {
if(!player.isConnected()) continue;
io.to(player.guildId).emit("/PLAYER/UPDATE", player.getState())
wlog.log("Envoi de l'état du player de la guilde : " + player.guildId + " à tous les utilisateurs connectés")
}
@@ -68,8 +69,8 @@ function init() {
// Make sure Discord Bot is loaded and make an interruption until it is loaded
while(!discordBot.getClient().isReady()) {
wlog.warn("Attente de traitement : "+ socket.id + " : Le bot Discord n'est pas encore chargé, attente de 1 seconde...")
await new Promise(resolve => setTimeout(resolve, 1000))
wlog.warn("Attente de traitement : "+ socket.id + " : Le bot Discord n'est pas encore chargé, attente de 3 seconde... (Avoid Rate Limit)")
await new Promise(resolve => setTimeout(resolve, 3000))
}
wlog.log(`Connexion d'un client : ${socket.id}`)
@@ -152,8 +153,13 @@ function init() {
return
}
await users.updateGuilds(socketUser.identity.id)
await users.updateIdentity(socketUser.identity.id)
if (!(await users.updateGuilds(socketUser.identity.id)) || !(await users.updateIdentity(socketUser.identity.id))) {
wlog.error("Erreur lors de la mise à jour des informations de l'utilisateur : " + socketUser.identity.id);
socket.emit("UPDATE_ERROR", "Error updating user information");
wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
socket.disconnect();
return;
}
}
socketUser = users.getUserByToken(token)
@@ -220,14 +226,14 @@ function init() {
// PLAYERS
//CHECKED : 03/05/2025
IORequest("/PLAYER/PREVIOUS/LIST", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
const list = new List(guildId)
IOAnswer("/PLAYER/PREVIOUS/LIST", list.getPrevious())
})
//TODO: Faire les autres reqêtes sur la liste
// ChECKED : 03/05/2025
IORequest("/PLAYER/JOIN", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
wlog.log("L'utilisateur '" + socketUser.identity.username + "' rejoint la liste d'écoute du player de la guilde : " + guildId)
@@ -238,37 +244,49 @@ function init() {
}
})
socket.join(guildId)
IOAnswer("PLAYER_STATE", true)
IOAnswer("/PLAYER/JOIN", true)
process.emit("PLAYERS_UPDATE")
})
IORequest("/PLAYER/STATE", (guildId) => {
handlePlayerAction(guildId, async (player) => await player.getState(), "/PLAYER/STATE");
// CHECKED : 03/05/2025
IORequest("/PLAYER/STATE", async (guildId) => {
const player = await verifyPlayerAction(guildId)
if(!player) return IOAnswer("/PLAYER/STATE", false)
IOAnswer("/PLAYER/STATE", await player.getState())
})
// CHECKED : 03/05/2025
IORequest("/PLAYER/PAUSE", (guildId) => {
handlePlayerAction(guildId, (player) => player.pause(), "/PLAYER/PAUSE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/BACKWARD", (guildId) => {
handlePlayerAction(guildId, (player) => player.previous(), "/PLAYER/BACKWARD");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/FORWARD", (guildId) => {
handlePlayerAction(guildId, (player) => player.skip(), "/PLAYER/FORWARD");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/LOOP", (guildId) => {
handlePlayerAction(guildId, (player) => player.setLoop(), "/PLAYER/LOOP");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/SHUFFLE", (guildId) => {
handlePlayerAction(guildId, (player) => player.setShuffle(), "/PLAYER/SHUFFLE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/DISCONNECT", (guildId) => {
handlePlayerAction(guildId, (player) => player.leave(), "/PLAYER/DISCONNECT");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/CHANNEL/CHANGE", (guildId) => {
handlePlayerAction(guildId, (player) => {
const channel = getUserChannel()
@@ -280,6 +298,7 @@ function init() {
}, "/PLAYER/CHANNEL/CHANGE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/SEEK", (data) => {
if(!data) return IOAnswer("/PLAYER/SEEK", false)
const {guildId, time} = data
@@ -296,14 +315,17 @@ function init() {
}, "/PLAYER/SEEK");
});
// CHECKED : 04/05/2025
IORequest("/QUEUE/PLAY/NOW", (data) => {
if(!data) return IOAnswer("/QUEUE/PLAY/NOW", false)
const {guildId, song} = data
if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false)
const {guildId, index, listType} = data
if(!index) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!guildId) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!listType) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/QUEUE/PLAY", false)
var song;
if(listType == "previous") {
const previous = player.queue.getPrevious()
song = previous[index]
@@ -311,11 +333,13 @@ function init() {
const next = player.queue.getNext()
song = next[index]
}
if(!song) return IOAnswer("/QUEUE/PLAY", false)
player.add(song)
if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(listType == "next") player.queue.removeNextByIndex(index)
player.play(song)
IOAnswer("/QUEUE/PLAY/NOW", true)
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/DELETE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/DELETE", false)
const {guildId, index} = data
@@ -325,13 +349,15 @@ function init() {
const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/DELETE", false);
player.queue.removeNextByIndex(index)
})
}, "/QUEUE/NEXT/DELETE")
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/DELETEALL", (guildId) => {
handlePlayerAction(guildId, (player) => player.queue.clearNext())
handlePlayerAction(guildId, (player) => player.queue.clearNext(), "/QUEUE/NEXT/DELETEALL")
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/MOVE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/MOVE", false)
const {guildId, index, newIndex} = data
@@ -342,7 +368,7 @@ function init() {
const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/MOVE", false);
player.queue.moveNext(index, newIndex)
})
}, "/QUEUE/NEXT/MOVE")
})
// SEARCH
@@ -352,10 +378,14 @@ function init() {
IOAnswer("/SEARCH", await Finder.search(query, true))
})
// CHECKED : 03/05/2025
IORequest("/SEARCH/PLAY", async (data) => {
if(!data) return IOAnswer("/SEARCH/PLAY", false)
const {guildId, song, now} = data
var {guildId, song, now} = data
if(!song) return IOAnswer("/SEARCH/PLAY", false)
if(typeof song == "string") {
song = JSON.parse(song)
}
if(!guildId) return IOAnswer("/SEARCH/PLAY", false)
if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId)
@@ -368,6 +398,20 @@ function init() {
IOAnswer("/SEARCH/PLAY", true)
})
// CHECKED : 05/05/2025
IORequest("/SEARCH/PLAYLIST", async (data) => {
if(!data) return IOAnswer("/SEARCH/PLAYLIST", false)
const {url, now, guildId} = data
if(!url) return IOAnswer("/SEARCH/PLAYLIST", false)
if(!guildId) return IOAnswer("/SEARCH/PLAYLIST", false)
const playlist = await Finder.search(url, true, "PLAYLIST")
if(!playlist) return IOAnswer("/SEARCH/PLAYLIST", false)
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/SEARCH/PLAYLIST", false)
player.readPlaylist(playlist, now)
IOAnswer("/SEARCH/PLAYLIST", true)
})
// PLAYLISTS
@@ -446,7 +490,8 @@ function init() {
IOAnswer("/PLAYLISTS/REMOVE_SONG", true)
})
IORequest("/PLAYLISTS/PLAY", (data) => {
// CHECKED : 05/05/2025
IORequest("/PLAYLISTS/PLAY", async (data) => {
if(!data) return IOAnswer("/PLAYLISTS/PLAY", false)
const {name, guildId, now} = data
if(!name || !guildId) return IOAnswer("/PLAYLISTS/PLAY", false)
@@ -454,7 +499,7 @@ function init() {
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/PLAY", false)
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/PLAYLISTS/PLAY", false)
if(!await connectToPlayer(guildId, player)) return IOAnswer("/PLAYLISTS/PLAY", false)
player.readPlaylist(playlist, now)
IOAnswer("/PLAYLISTS/PLAY", true)
})
@@ -575,6 +620,7 @@ function init() {
const member = membersVoices.get(socketUser.identity.id)
if(member) {
const channelId = member.channelId
const guildId = member.guildId
const channel = discordBot.getChannel(guildId, channelId)
if(!channel) {
wlog.warn("Le channel vocal n'existe pas : " + channelId)
@@ -599,6 +645,17 @@ function init() {
return true
}
async function verifyPlayerAction(guildId) {
if (!checkUserGuild(socketUser, guildId)) return null;
const player = players.getPlayer(guildId);
if (player) {
return player;
} else {
wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`);
return null;
}
}
function checkUserGuild(socketUser, guildId) {
// Check if the guildId is referenced in the bot guilds
@@ -622,20 +679,22 @@ function init() {
return true
}
/**
/**
* @param {function(Player)} action - The action to perform on the player.
*/
async function handlePlayerAction(guildId, action, actionName) {
async function handlePlayerAction(guildId, action, actionName) {
if (!checkUserGuild(socketUser, guildId)) return;
const player = players.getPlayer(guildId);
const player = players.getPlayer(guildId);
if (player) {
await action(player);
wlog.log(`L'utilisateur '${socketUser.identity.username}' effectue l'action '${actionName}' sur le player de la guilde : ${guildId}`);
IOAnswer(actionName, true);
await action(player);
wlog.log(`L'utilisateur '${socketUser.identity.username}' effectue l'action '${actionName}' sur le player de la guilde : ${guildId}`);
IOAnswer(actionName, true);
} else {
wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`);
IOAnswer(actionName, false);
wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`);
IOAnswer(actionName, false);
}
}
}
@@ -683,13 +742,12 @@ function init() {
wlog.step.end("server_init")
})
function AdminRequest(GRname, GRvalue) {
io.to("ADMIN").emit("ALWAYS/" + GRname, GRvalue)
}
function addGuildConnectedUser(user, guilds) {
// Check if guilds is iterable
if(!guilds || !guilds[Symbol.iterator]) {
wlog.warn("Les guilds ne sont pas itérables")
return
}
for(var guild of guilds) {
if(!guildConnectedUsers.has(guild)) {
guildConnectedUsers.set(guild.id, new Array())

View File

@@ -169,59 +169,46 @@ async function refreshAllUserInformation() {
await loadUsers();
clog.log("Récupération des informations de tous les utilisateurs...");
for (const user of userList) {
await refreshUserInformation(user.identity.id);
await updateCredientials(user.identity.id);
}
saveUsers();
}
async function refreshUserInformation(id) {
async function updateCredientials(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Récupération (Refresh) des informations de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
clog.log(`Mise à jour des informations d'authentification Discord de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const refresh_token = user.auth.refresh_token;
const authCredientials = await discordAuth.refreshToken(refresh_token);
if(authCredientials) {
user.auth = authCredientials;
const guilds = await discordAuth.getUserGuilds(authCredientials);
const identity = await discordAuth.getUserIdentity(authCredientials);
if(identity) {
user.identity = identity;
clog.log(`Récupération réussie des informations de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la récupération des informations de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
if(guilds) {
user.guilds = guilds;
clog.log(`Récupération réussie des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la récupération des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.guilds = user.guilds;
// Check if the token is expired
const auth = await discordAuth.refreshToken(user.auth.refresh_token);
if (auth) {
// Check Rate limit by checking if auth.message exists
if(typeof auth.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${auth.message}`);
return null;
}
user.auth = auth;
clog.log(`Mise à jour réussie des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id})`);
} else {
clog.warn(`Erreur lors de la récupération du token d'accès pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
// Delete tokens to oblige the user to reauthenticate
// Clear auth
user.destroyAuth();
return null;
clog.warn(`Erreur lors de la mise à jour des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
} else {
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
}
}
else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
saveUsers();
return user.auth;
}
async function updateGuilds(id) {
const user = getUserById(id);
if (!user) {
@@ -232,11 +219,16 @@ async function updateGuilds(id) {
if (user.auth) {
const guilds = await discordAuth.getUserGuilds(user.auth);
if(guilds) {
if(typeof guilds.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${guilds.message}`);
return null;
}
user.guilds = guilds;
clog.log(`Mise à jour réussie des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
@@ -246,6 +238,7 @@ async function updateGuilds(id) {
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
saveUsers();
return user.guilds;
@@ -261,11 +254,17 @@ async function updateIdentity(id) {
if (user.auth) {
const identity = await discordAuth.getUserIdentity(user.auth);
if(identity) {
// Check Rate limit by checking if identity.message exists
if(typeof identity.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${identity.message}`);
return null;
}
user.identity = identity;
clog.log(`Mise à jour réussie de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
@@ -275,6 +274,7 @@ async function updateIdentity(id) {
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
saveUsers();
return user.identity;
@@ -525,7 +525,7 @@ module.exports = {
removeToken,
getSimpleUsers,
getSimpleUser,
refreshUserInformation,
updateCredientials,
refreshAllUserInformation,
updateGuilds,
updateIdentity