Version 0.1.0 - Mise en place de Discord.js
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -141,3 +141,4 @@ docs/_book
 | 
			
		||||
# TODO: where does this rule come from?
 | 
			
		||||
test/
 | 
			
		||||
 | 
			
		||||
data/
 | 
			
		||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							@@ -1,3 +1,20 @@
 | 
			
		||||
# chopin
 | 
			
		||||
# **Subsonics - Chopin** 
 | 
			
		||||
 | 
			
		||||
Discord Bot for music - Fetching everywhere !
 | 
			
		||||
> Cette version est une refonte complète et intégrale de [Subsonics - Web](https://git.raphix.fr/subsonics/web)
 | 
			
		||||
 | 
			
		||||
### Bienvenue sur Chopin, la nouvelle version de Subsonics.
 | 
			
		||||
 | 
			
		||||
### **Fonctionnalités**
 | 
			
		||||
 | 
			
		||||
> - Lecture de vidéos depuis Youtube, Spotify et SoundClound
 | 
			
		||||
> - Lecture de fichiers locaux *(Uniquement sur le site)*
 | 
			
		||||
> - Gestion et lecture de playlist 
 | 
			
		||||
> - Accéder à votre propre historique et à l'historique du Bot
 | 
			
		||||
> - Affichage des paroles de la musique en cours
 | 
			
		||||
> - Une interface refaite pour toutes les platformes.
 | 
			
		||||
> - Récupération de vos recommendations & Playlists Spotify / Youtube
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Le FrontEnd est gérée par VueJS ✌️et le BackEnd a été entièrement refait localement pour des réponses plus rapide et plus stable
 | 
			
		||||
 | 
			
		||||
[CHANGELOG](https://git.raphix.fr/subsonics/chopin/src/branch/main/changelog.md)
 | 
			
		||||
							
								
								
									
										1717
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1717
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										30
									
								
								backend/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								backend/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "chopin-backend",
 | 
			
		||||
  "version": "0.1.0",
 | 
			
		||||
  "description": "Discord Bot for music - Fetching everywhere !",
 | 
			
		||||
  "main": "src/main.js",
 | 
			
		||||
  "nodemonConfig": {
 | 
			
		||||
    "ext": "js, html",
 | 
			
		||||
    "ignore": [
 | 
			
		||||
      "*.json",
 | 
			
		||||
      "*.html"
 | 
			
		||||
    ],
 | 
			
		||||
    "delay": "2000000"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "start": "nodemon src/main.js"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [],
 | 
			
		||||
  "author": "Raphix",
 | 
			
		||||
  "license": "ISC",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "cors": "^2.8.5",
 | 
			
		||||
    "discord.js": "^14.18.0",
 | 
			
		||||
    "express": "^4.21.2",
 | 
			
		||||
    "loguix": "^1.4.2",
 | 
			
		||||
    "nodemon": "^3.1.9",
 | 
			
		||||
    "socket.io": "^4.8.1",
 | 
			
		||||
    "uuid": "^11.1.0",
 | 
			
		||||
    "webmetrik": "^0.1.4"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								backend/src/discord/Activity.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								backend/src/discord/Activity.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
const bot = require('./Bot')
 | 
			
		||||
const dlog = require('loguix').getInstance('Discord')
 | 
			
		||||
const {ActivityType} = require('discord.js')
 | 
			
		||||
 | 
			
		||||
function getActivity() {
 | 
			
		||||
    const client = bot.getClient()
 | 
			
		||||
    return client.user.presence.activities[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set All type of activities
 | 
			
		||||
 | 
			
		||||
function setMusicActivity(songName, artistName, imageUrl) {
 | 
			
		||||
    const client = bot.getClient()
 | 
			
		||||
    client.user.setActivity(`${songName} - ${artistName}`,{
 | 
			
		||||
            type: ActivityType.Listening,
 | 
			
		||||
            /*assets: {
 | 
			
		||||
                largeImage: imageUrl,
 | 
			
		||||
                largeText: songName
 | 
			
		||||
            }*/
 | 
			
		||||
    });
 | 
			
		||||
    dlog.log(`Activité mise à jour : ${songName} - ${artistName}`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function idleActivity() {
 | 
			
		||||
    const client = bot.getClient()
 | 
			
		||||
    client.user.setActivity("le silence absolu", {
 | 
			
		||||
        type: ActivityType.Listening
 | 
			
		||||
       
 | 
			
		||||
    });
 | 
			
		||||
    dlog.log(`Activité mise à jour : rien`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = {getActivity, setMusicActivity, idleActivity}
 | 
			
		||||
							
								
								
									
										78
									
								
								backend/src/discord/Bot.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								backend/src/discord/Bot.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
const { Client, GatewayIntentBits, Collection, ActivityType, REST, Routes } = require("discord.js")
 | 
			
		||||
const fs = require("node:fs")
 | 
			
		||||
const path = require("path")
 | 
			
		||||
const { __glob } = require("../utils/GlobalVars")
 | 
			
		||||
const { LogType } = require("loguix")
 | 
			
		||||
const config = require("../utils/Database/Configuration")
 | 
			
		||||
const metric = require("webmetrik") 
 | 
			
		||||
 | 
			
		||||
const dlog = new LogType("Discord")
 | 
			
		||||
 | 
			
		||||
const client = new Client({
 | 
			
		||||
    intents:[GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers],
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Getter for the client
 | 
			
		||||
function getClient() {
 | 
			
		||||
    return client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    
 | 
			
		||||
    client.once('ready', () => {
 | 
			
		||||
        dlog.log("Connexion au Bot Discord réussi ! Connecté en tant que : " + client.user.tag)
 | 
			
		||||
 | 
			
		||||
        const Activity = require("./Activity")
 | 
			
		||||
        Activity.idleActivity()
 | 
			
		||||
 | 
			
		||||
        const CommandUpdater = require("./CommandUpdater")
 | 
			
		||||
        CommandUpdater.init()
 | 
			
		||||
 | 
			
		||||
        const commandManager = client.application.commands;
 | 
			
		||||
 | 
			
		||||
        if (!commandManager) {
 | 
			
		||||
            dlog.error('Command manager not available.');
 | 
			
		||||
                
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            commandManager.set([]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        dlog.step.end("d_init")
 | 
			
		||||
   
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    client.on("interactionCreate", (interaction) => {
 | 
			
		||||
        
 | 
			
		||||
        if(!interaction.isCommand()) return;
 | 
			
		||||
 | 
			
		||||
        var numberOfCommands = new metric.Metric("numberOfCommands", "Nombre de commandes éxécutées")
 | 
			
		||||
        numberOfCommands.setValue(numberOfCommands.getValue() + 1)
 | 
			
		||||
 | 
			
		||||
        const command = client.commands.get(interaction.commandName)
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
            // Create a metric to count the number of commands executed by each user
 | 
			
		||||
            const userCommand = new metric.Metric("userCommand_" + interaction.member.user.username, "Nombre de commandes éxécutées par l'utilisateur : " + interaction.member.user.username)
 | 
			
		||||
            userCommand.setValue(userCommand.getValue() + 1)
 | 
			
		||||
            dlog.log(interaction.member.user.username + "-> /" + interaction.commandName)
 | 
			
		||||
            command.execute(client, interaction)
 | 
			
		||||
        } catch(error) {
 | 
			
		||||
 | 
			
		||||
            dlog.error(interaction.member.user.username + "-> /" + interaction.commandName + " : ERREUR RENCONTRE")
 | 
			
		||||
            dlog.error(error)
 | 
			
		||||
            interaction.reply({content:"Erreur lors de l'éxécution de la commande !", ephemeral: true})
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    client.login(config.getToken())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {init, getClient}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										73
									
								
								backend/src/discord/Command.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								backend/src/discord/Command.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
const { SlashCommandBuilder} = require("discord.js");
 | 
			
		||||
 | 
			
		||||
class Command {
 | 
			
		||||
    name;
 | 
			
		||||
    description;
 | 
			
		||||
    callback;
 | 
			
		||||
    data;
 | 
			
		||||
    constructor(name, description, callback, options) {
 | 
			
		||||
        this.name = name
 | 
			
		||||
        this.description = description
 | 
			
		||||
        this.callback = callback
 | 
			
		||||
        this.options = options
 | 
			
		||||
        const SlashCommand = new SlashCommandBuilder()
 | 
			
		||||
        .setName(name)
 | 
			
		||||
        .setDescription(description)
 | 
			
		||||
        // Options is an array with the following structure: [{name: "name", description: "description", type: "type", required: true/false, choices: [{name: "name", value: "value"}]}]
 | 
			
		||||
        if (options) {
 | 
			
		||||
            options.forEach(SelOption => {
 | 
			
		||||
                if(SelOption.type === "STRING") {
 | 
			
		||||
                    SlashCommand.addStringOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "INTEGER") {
 | 
			
		||||
                    SlashCommand.addIntegerOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "BOOLEAN") {
 | 
			
		||||
                    SlashCommand.addBooleanOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "USER") {
 | 
			
		||||
                    SlashCommand.addUserOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "CHANNEL") {
 | 
			
		||||
                    SlashCommand.addChannelOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "ROLE") {
 | 
			
		||||
                    SlashCommand.addRoleOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "NUMBER") {
 | 
			
		||||
                    SlashCommand.addNumberOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "SUB_COMMAND") {
 | 
			
		||||
                    SlashCommand.addSubcommand(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "SUB_COMMAND_GROUP") {
 | 
			
		||||
                    SlashCommand.addSubcommandGroup(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "MENTIONABLE") {
 | 
			
		||||
                    SlashCommand.addMentionableOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required))
 | 
			
		||||
                }
 | 
			
		||||
                if(SelOption.type === "CHOICES") {
 | 
			
		||||
                    let choices = []
 | 
			
		||||
                    SelOption.choices.forEach(SelChoice => {
 | 
			
		||||
                        choices.push({name: SelChoice.name, value: SelChoice.value})
 | 
			
		||||
                    })
 | 
			
		||||
                    SlashCommand.addStringOption(option => option.setName(SelOption.name).setDescription(SelOption.description).setRequired(SelOption.required).addChoices(choices))
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.data = {data: SlashCommand,  async execute(client, interaction) {callback(client, interaction)}}
 | 
			
		||||
            
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getData() {
 | 
			
		||||
        return this.data
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getName() {
 | 
			
		||||
        return this.name
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {Command}
 | 
			
		||||
							
								
								
									
										78
									
								
								backend/src/discord/CommandUpdater.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								backend/src/discord/CommandUpdater.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
function init() {
 | 
			
		||||
 | 
			
		||||
const bot = require("./Bot")
 | 
			
		||||
const client = bot.getClient()
 | 
			
		||||
const { Collection, REST, Routes } = require("discord.js")
 | 
			
		||||
const fs = require("node:fs")
 | 
			
		||||
const path = require("path")
 | 
			
		||||
const {__glob} = require("../utils/GlobalVars")
 | 
			
		||||
const dlog = require("loguix").getInstance("Discord")
 | 
			
		||||
const config = require("../utils/Database/Configuration")
 | 
			
		||||
 | 
			
		||||
client.commands = new Collection()
 | 
			
		||||
    dlog.step.init("d_init", "Initialisation du Bot Discord")
 | 
			
		||||
    dlog.step.init("d_get_commands", "Récupération des commandes en local depuis : " + __glob.COMMANDS)
 | 
			
		||||
 | 
			
		||||
    const commands = [];
 | 
			
		||||
    // Grab all the command files from the commands directory you created earlier
 | 
			
		||||
    const commandsPath = __glob.COMMANDS
 | 
			
		||||
    const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
 | 
			
		||||
 | 
			
		||||
    for (const file of commandFiles) {
 | 
			
		||||
        const cmd = require(commandsPath + path.sep + file);
 | 
			
		||||
        client.commands.set(cmd.command.getName(), cmd.command.getData())
 | 
			
		||||
 | 
			
		||||
        commands.push(cmd.command.getData().data.toJSON());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    dlog.step.end("d_get_commands")
 | 
			
		||||
 | 
			
		||||
    const rest = new REST().setToken(config.getToken());
 | 
			
		||||
    
 | 
			
		||||
    if(commands.length != 0) {
 | 
			
		||||
 | 
			
		||||
    (async () => {
 | 
			
		||||
        try {
 | 
			
		||||
           
 | 
			
		||||
        
 | 
			
		||||
            const guilds = client.guilds.cache.map(guild => guild.id);
 | 
			
		||||
 | 
			
		||||
            dlog.step.init("d_commands_refresh", `Refreshing ${guilds.length} guilds (/) commands.`);
 | 
			
		||||
            for (const guildId of guilds) {
 | 
			
		||||
                const data = await rest.put(
 | 
			
		||||
                    Routes.applicationGuildCommands(client.user.id, guildId),
 | 
			
		||||
                    { body: commands },
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Log the guilds where the commands have been refreshed with number of commands
 | 
			
		||||
                dlog.log(`Refreshed "${data.length}" commands in guild "${guildId} - ${client.guilds.cache.get(guildId).name}"`);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
           
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            dlog.step.end("d_commands_refresh")
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // And of course, make sure you catch and log any errors!
 | 
			
		||||
            dlog.error(error)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
       
 | 
			
		||||
    })();
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        dlog.warn("Aucune commande à envoyer à Discord !")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    rest.on("rateLimited", (datawarn) => {
 | 
			
		||||
        dlog.warn("REST - Limite de requête atteinte ! TimeToReset : " + datawarn.timeToReset);
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {init}
 | 
			
		||||
							
								
								
									
										36
									
								
								backend/src/discord/Commands/About.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								backend/src/discord/Commands/About.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
const { Command } = require('../Command');
 | 
			
		||||
const { Embed } = require('../Embed');
 | 
			
		||||
const { __glob } = require("../../utils/GlobalVars");
 | 
			
		||||
const packageJson = require(__glob.PACKAGEINFO);
 | 
			
		||||
 | 
			
		||||
const command = new Command("about", "Affiche des informations sur le bot", (client, interaction) => {
 | 
			
		||||
 | 
			
		||||
    const uptime = process.uptime();
 | 
			
		||||
    const hours = Math.floor(uptime / 3600);
 | 
			
		||||
    const minutes = Math.floor((uptime % 3600) / 60);
 | 
			
		||||
    const seconds = Math.floor(uptime % 60);
 | 
			
		||||
 | 
			
		||||
    const embed = new Embed()
 | 
			
		||||
    embed.setColor(0xb0f542)
 | 
			
		||||
    embed.setThumbnail("https://cdn.discordapp.com/avatars/" + client.user.id + "/" + client.user.avatar + ".png")
 | 
			
		||||
    embed.setTitle('Subsonics - Chopin')
 | 
			
		||||
    embed.addField('Informations',"")
 | 
			
		||||
    embed.addField('Version', packageJson.version + "    ", true)
 | 
			
		||||
    embed.addField('Uptime', `${hours}h ${minutes}m ${seconds}s    `, true)
 | 
			
		||||
    embed.addField("Ping", `${client.ws.ping} ms    `, true)
 | 
			
		||||
    embed.addField("Réalisé par", "Raphix - 2025", true)
 | 
			
		||||
    embed.addColumn()
 | 
			
		||||
    embed.addField('Versions',"")
 | 
			
		||||
    embed.addField('Node.js', process.version,true)
 | 
			
		||||
    embed.addField('Discord.js', packageJson.dependencies["discord.js"].replace("^", ""),true)
 | 
			
		||||
    embed.addColumn()
 | 
			
		||||
    embed.addField('Webmetrik', packageJson.dependencies["webmetrik"].replace("^", ""),true)
 | 
			
		||||
    embed.addField('Loguix', packageJson.dependencies["loguix"].replace("^", ""),true)
 | 
			
		||||
    embed.addColumn()
 | 
			
		||||
 | 
			
		||||
    embed.send(interaction)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
module.exports = {command}
 | 
			
		||||
							
								
								
									
										34
									
								
								backend/src/discord/Commands/Help.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								backend/src/discord/Commands/Help.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
const { Command } = require('../Command');
 | 
			
		||||
const { Embed } = require('../Embed');
 | 
			
		||||
 | 
			
		||||
const command = new Command("help", "Affiche la liste des commandes", (client, interaction) => {
 | 
			
		||||
    
 | 
			
		||||
    const embed = new Embed()
 | 
			
		||||
    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 !**")
 | 
			
		||||
    embed.addField('**Liste des commandes :**',"")
 | 
			
		||||
    client.commands.forEach(command => {
 | 
			
		||||
        let CommandName = command.data.name
 | 
			
		||||
 | 
			
		||||
        if (command.data.options) {
 | 
			
		||||
            command.data.options.forEach(option => {
 | 
			
		||||
                if (option.choices) {
 | 
			
		||||
                    let choices = []
 | 
			
		||||
                    option.choices.forEach(choice => {
 | 
			
		||||
                        choices.push(choice.name)
 | 
			
		||||
                    })
 | 
			
		||||
                    CommandName += " " + choices.join(" | ")
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        embed.addField("/" + CommandName, command.data.description)
 | 
			
		||||
        
 | 
			
		||||
    })
 | 
			
		||||
    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)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
module.exports = {command}
 | 
			
		||||
							
								
								
									
										36
									
								
								backend/src/discord/Commands/Report.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								backend/src/discord/Commands/Report.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
const { Command } = require('../Command');
 | 
			
		||||
const { Embed } = require('../Embed');
 | 
			
		||||
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()
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    result.then((res) => {
 | 
			
		||||
        if(!res) {
 | 
			
		||||
            embed.setColor(0xc20f02)
 | 
			
		||||
            embed.setTitle('Erreur')
 | 
			
		||||
            embed.setDescription("Une erreur est survenue lors de l'envoi du rapport")
 | 
			
		||||
            
 | 
			
		||||
        } else {
 | 
			
		||||
            embed.setColor(0x00ff66)
 | 
			
		||||
            embed.setTitle('Rapport envoyé')
 | 
			
		||||
            embed.setDescription("Votre rapport a bien été envoyé !")
 | 
			
		||||
           
 | 
			
		||||
        }
 | 
			
		||||
        embed.send(interaction)
 | 
			
		||||
    })
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
}, 
 | 
			
		||||
[{type: "CHOICES", name: "type", description: "Type", required: true, choices: 
 | 
			
		||||
    [{name: "Bug", value: "bug"}, 
 | 
			
		||||
     {name: "Suggestion", value: "sugguestion"}],
 | 
			
		||||
 }, 
 | 
			
		||||
 {type: "STRING", name: "description", description: "Description du problème", required: true}]
 | 
			
		||||
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
module.exports = {command}
 | 
			
		||||
							
								
								
									
										14
									
								
								backend/src/discord/Commands/Web.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend/src/discord/Commands/Web.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
const { Command } = require('../Command');
 | 
			
		||||
const { Embed } = require('../Embed');
 | 
			
		||||
 | 
			
		||||
const command = new Command("web", "Affiche le lien vers le site web pour contrôler le bot", (client, interaction) => {
 | 
			
		||||
    const embed = new Embed()
 | 
			
		||||
    embed.setColor(0xffffff)
 | 
			
		||||
    embed.setTitle('Subsonics - Chopin')
 | 
			
		||||
    embed.addBotPicture(client)
 | 
			
		||||
    embed.addField('Lien',"https://subsonics.raphix.fr/")
 | 
			
		||||
    embed.send(interaction)
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
module.exports = {command}
 | 
			
		||||
							
								
								
									
										89
									
								
								backend/src/discord/Embed.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								backend/src/discord/Embed.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
const { EmbedBuilder } = require("discord.js");
 | 
			
		||||
 | 
			
		||||
class Embed {
 | 
			
		||||
    fields;
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.embed = new EmbedBuilder().setTimestamp()
 | 
			
		||||
        this.fields = []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setTitle(title) {
 | 
			
		||||
        this.embed.setTitle(title)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setDescription(description) {
 | 
			
		||||
        this.embed.setDescription(description)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setAuthor(author) {
 | 
			
		||||
        this.embed.setAuthor(author)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setColor(r, g, b) {
 | 
			
		||||
        // if only R is provided, set color with R as hex else set color with RGB
 | 
			
		||||
        if (g === undefined && b === undefined) {
 | 
			
		||||
            this.embed.setColor(r)
 | 
			
		||||
            return this
 | 
			
		||||
        } else {
 | 
			
		||||
            // Transforme r, g, b in one 0xRRGGBB value
 | 
			
		||||
            
 | 
			
		||||
            r = Math.max(0, Math.min(255, r));
 | 
			
		||||
            g = Math.max(0, Math.min(255, g));
 | 
			
		||||
            b = Math.max(0, Math.min(255, b));
 | 
			
		||||
 | 
			
		||||
            // Shift the values to their respective positions in a 24-bit number
 | 
			
		||||
            const hexNumber = (r << 16) + (g << 8) + b;
 | 
			
		||||
            
 | 
			
		||||
            this.embed.setColor(hexNumber)
 | 
			
		||||
         
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
         
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setFooter(footer) {
 | 
			
		||||
        this.embed.setFooter(footer)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setImage(imageUrl) {
 | 
			
		||||
        this.embed.setImage(imageUrl)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setThumbnail(thumbnailUrl) {
 | 
			
		||||
        this.embed.setThumbnail(thumbnailUrl)
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addBotPicture(client) {
 | 
			
		||||
        this.embed.setThumbnail("https://cdn.discordapp.com/avatars/" + client.user.id + "/" + client.user.avatar + ".png")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addField(name, value, inline) {
 | 
			
		||||
        if(!inline) inline = false;
 | 
			
		||||
        this.fields.push({name: name, value: value, inline: inline})
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    addColumn() {
 | 
			
		||||
        this.fields.push({name: '\u200B', value: '\u200B', inline: true})
 | 
			
		||||
        return this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    build() {
 | 
			
		||||
        //Add Fields to an object 
 | 
			
		||||
        this.embed.addFields(this.fields)
 | 
			
		||||
        return this.embed
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    send(interaction) {
 | 
			
		||||
        interaction.reply({embeds: [this.build()]})
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {Embed}
 | 
			
		||||
							
								
								
									
										51
									
								
								backend/src/discord/ReportSender.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								backend/src/discord/ReportSender.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
const config = require("../utils/Database/Configuration");
 | 
			
		||||
const { __glob } = require("../utils/GlobalVars");
 | 
			
		||||
const discord = require("./Bot")
 | 
			
		||||
const {Embed} = require("./Embed")
 | 
			
		||||
const log = require("loguix")
 | 
			
		||||
const packageJson = require(__glob.PACKAGEINFO)
 | 
			
		||||
 | 
			
		||||
class Report {
 | 
			
		||||
    client = discord.getClient();
 | 
			
		||||
    report_channel = config.getReportChannel();
 | 
			
		||||
    report_contact = config.getReportContact();
 | 
			
		||||
    embed;
 | 
			
		||||
    constructor(provider, level, desc) {
 | 
			
		||||
        const embed = new Embed()
 | 
			
		||||
        embed.setDescription('**Version : **' + packageJson.version)
 | 
			
		||||
        embed.setTitle("Rapport de : " + provider)
 | 
			
		||||
 | 
			
		||||
        var levelString = null
 | 
			
		||||
        if(level == "bug") {
 | 
			
		||||
            levelString = "Bug"
 | 
			
		||||
            embed.setColor(0xc20f02)
 | 
			
		||||
        } else {
 | 
			
		||||
            levelString = "Suggestion"
 | 
			
		||||
            embed.setColor(20, 50, 200) // 
 | 
			
		||||
              
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        embed.addField("Type", levelString)
 | 
			
		||||
        embed.addField("Description", desc)
 | 
			
		||||
        this.embed = embed
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async send() {
 | 
			
		||||
        if(!this.report_channel || this.report_channel == "") {
 | 
			
		||||
            log.getInstance("Discord").error("Pas de channel de rapport configuré")
 | 
			
		||||
            return false
 | 
			
		||||
        } else {
 | 
			
		||||
            const channel = await this.client.channels.fetch(this.report_channel)
 | 
			
		||||
            channel.send({embeds: [this.embed.build()]})
 | 
			
		||||
            if(this.report_contact && this.report_contact != "") channel.send({content: "<@" + this.report_contact + ">"})
 | 
			
		||||
            return true
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
       
 | 
			
		||||
       
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {Report}
 | 
			
		||||
							
								
								
									
										24
									
								
								backend/src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								backend/src/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
/**
 | 
			
		||||
 * [Subsonics Chopin - Backend] - Raphix - 02/2025
 | 
			
		||||
 * File: main.js
 | 
			
		||||
 * Description: Main entry point for the backend application
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const { LogType } = require('loguix');
 | 
			
		||||
const { __glob } = require("./utils/GlobalVars")
 | 
			
		||||
require("loguix").setup(__glob.LOGS, __glob.PACKAGEINFO)
 | 
			
		||||
const config = require("./utils/Database/Configuration")
 | 
			
		||||
const metric = require("webmetrik")
 | 
			
		||||
metric.setMetricFile(__glob.METRIC_FILE)
 | 
			
		||||
metric.publishMetrics("8001", "raphraph")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// SETUP 
 | 
			
		||||
 | 
			
		||||
setup();
 | 
			
		||||
 | 
			
		||||
function setup() {
 | 
			
		||||
    const DiscordBot = require("./discord/Bot")
 | 
			
		||||
    DiscordBot.init()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								backend/src/utils/Database/Configuration.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								backend/src/utils/Database/Configuration.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
const {Database} = require("./Database")
 | 
			
		||||
const {__glob} = require("../GlobalVars")
 | 
			
		||||
const {LogType} = require("loguix")
 | 
			
		||||
const path = require("path")
 | 
			
		||||
 | 
			
		||||
const clog = new LogType("Configuration")
 | 
			
		||||
 | 
			
		||||
const config = new Database("config", __glob.DATA  + path.sep + "config.json", {
 | 
			
		||||
    token: "",
 | 
			
		||||
    report: {
 | 
			
		||||
        channel : "",
 | 
			
		||||
        contact : ""
 | 
			
		||||
    }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function getToken() {
 | 
			
		||||
    return config.data.token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getReportChannel() {
 | 
			
		||||
    return config.data.report.channel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getReportContact() {
 | 
			
		||||
    return config.data.report.contact
 | 
			
		||||
}   
 | 
			
		||||
 | 
			
		||||
if(getToken() == "") {
 | 
			
		||||
    clog.error("Impossible de démarrer sans token valide")
 | 
			
		||||
    process.exit(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {getToken, getReportChannel, getReportContact}
 | 
			
		||||
							
								
								
									
										87
									
								
								backend/src/utils/Database/Database.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								backend/src/utils/Database/Database.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const { LogType } = require('loguix');
 | 
			
		||||
const { __glob } = require("../GlobalVars")
 | 
			
		||||
 | 
			
		||||
const AllDatabases = {}
 | 
			
		||||
 | 
			
		||||
const clog = new LogType("DataBase")
 | 
			
		||||
 | 
			
		||||
function getDatabase(name) {
 | 
			
		||||
    return AllDatabases[name]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Database {
 | 
			
		||||
    data;
 | 
			
		||||
    path;
 | 
			
		||||
    name;
 | 
			
		||||
    empty;
 | 
			
		||||
    constructor(name, path, empty) {
 | 
			
		||||
        if(name == undefined || path == undefined) throw clog.error("Impossible de créer une base de données sans nom ou sans chemin")
 | 
			
		||||
 | 
			
		||||
        clog.log(`Enregistrement de la base de données '${name}' contenu dans ${path}`)
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.path = path;
 | 
			
		||||
        this.data = {};
 | 
			
		||||
        if(empty) this.empty = empty; else this.empty = {}
 | 
			
		||||
        this.load()
 | 
			
		||||
        AllDatabases[name] = this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    load() {
 | 
			
		||||
        clog.log(`Chargement de la base de données '${this.name}'`)
 | 
			
		||||
        try {
 | 
			
		||||
            this.create()
 | 
			
		||||
            this.update()
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            clog.error(`Erreur lors du chargement de la base de données '${this.name}'`)
 | 
			
		||||
            clog.error(e)
 | 
			
		||||
        }
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    create() {
 | 
			
		||||
        try {
 | 
			
		||||
            if(!fs.existsSync(this.path)) {
 | 
			
		||||
                clog.warn(`Le fichier de la base de données '${this.name}' n'existe pas, création du fichier`)
 | 
			
		||||
                fs.writeFileSync(this.path, JSON.stringify(this.empty, null, 2))
 | 
			
		||||
            }
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            clog.error(`Erreur lors de la création de la base de données '${this.name}'`)
 | 
			
		||||
            clog.error(e)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    save() {
 | 
			
		||||
        try {
 | 
			
		||||
            clog.log(`Sauvegarde de la base de données '${this.name}'`)
 | 
			
		||||
            fs.writeFileSync(this.path, JSON.stringify(this.data, null, 2))
 | 
			
		||||
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            clog.error(`Erreur lors de la sauvegarde de la base de données '${this.name}'`)
 | 
			
		||||
            clog.error(e)
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    update() {
 | 
			
		||||
        try{
 | 
			
		||||
            clog.log(`Mise à jour de la base de données '${this.name}'`)
 | 
			
		||||
            let rawdata = fs.readFileSync(this.path);
 | 
			
		||||
            this.data = JSON.parse(rawdata);
 | 
			
		||||
            clog.log(`Base de donnée '${this.name}' chargée avec succès`)
 | 
			
		||||
            
 | 
			
		||||
        } catch(e) {
 | 
			
		||||
            clog.error(`Erreur lors de la mise à jour de la base de données '${this.name}'`)
 | 
			
		||||
            clog.error(e)
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = {Database, getDatabase}
 | 
			
		||||
							
								
								
									
										14
									
								
								backend/src/utils/GlobalVars.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend/src/utils/GlobalVars.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
const path = require("path")
 | 
			
		||||
const root = path.resolve(__dirname, '../../')
 | 
			
		||||
 | 
			
		||||
const __glob = {
 | 
			
		||||
    PACKAGEINFO: root + path.sep + "package.json",
 | 
			
		||||
    ROOT: root + + path.sep,
 | 
			
		||||
    SRC: root + path.sep + "src",
 | 
			
		||||
    LOGS: root + path.sep + "logs",
 | 
			
		||||
    DATA: root + path.sep + "data",
 | 
			
		||||
    COMMANDS: root + path.sep + "src" + path.sep + "discord" + path.sep + "commands",
 | 
			
		||||
    METRIC_FILE: root + path.sep + "data" + path.sep + "metrics.json"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {__glob}
 | 
			
		||||
							
								
								
									
										17
									
								
								changelog.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								changelog.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
# **Changelog**
 | 
			
		||||
 | 
			
		||||
- Express JS
 | 
			
		||||
- Vue JS
 | 
			
		||||
- Discord JS
 | 
			
		||||
- Player Youtube
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## **Légende de version** : 
 | 
			
		||||
 | 
			
		||||
* Version X.Y.Z
 | 
			
		||||
  > **X** : Indique une version de travail (Période d'activité) \
 | 
			
		||||
  > **Y** : Indique l'ajout d'une fonctionnalité \
 | 
			
		||||
  > **Z** : Indique la modification ou la réparation d'une fonctionnalité
 | 
			
		||||
* Tags
 | 
			
		||||
  > **-alpha** : Indique une version de dévelopement inutilisable \
 | 
			
		||||
  > **-rcX** : Indique une sous-version qui ne modifie rien mais qui peux corriger un bug de facon très superficiel 
 | 
			
		||||
		Reference in New Issue
	
	Block a user