diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/Includes/play.js b/Includes/play.js new file mode 100644 index 0000000..f7083a3 --- /dev/null +++ b/Includes/play.js @@ -0,0 +1,271 @@ +const ytdl = require("ytdl-core-discord"); +const { canModifyQueue, STAY_TIME } = require("../util/LanBot"); +const { MessageEmbed, MessageAttachment } = require("discord.js"); +const musicGif = new MessageAttachment('./assets/img/Music.gif'); +const dancingGif = new MessageAttachment('./assets/img/dancing.gif'); + +module.exports = { + async play(song, message) { + + + + let config; + + try { + config = require("../config"); + } catch (error) { + config = null; + } + + + + const PRUNING = config ? config.PRUNING : process.env.PRUNING; + + const queue = message.client.queue.get(message.guild.id); + + if (!song) { + setTimeout(function () { + if (queue.connection.dispatcher && message.guild.me.voice.channel) return; + queue.channel.leave(); + queue.textChannel.send("Fin de la liste de lecture ! Je vous abandonne !"); + }, STAY_TIME * 1000); + queue.textChannel.send("❌ La file d'attente est terminée.").catch(console.error); + return message.client.queue.delete(message.guild.id); + } + + let stream = null; + let streamType = song.url.includes("youtube.com") ? "opus" : "ogg/opus"; + + + try { + if (song.url.includes("youtube.com")) {stream = await ytdl(song.url, { + filter: format => ['251'], + highWaterMark: 1 << 25 + }), { + type: 'opus' + }; + } + + } catch (error) { + if (queue) { + queue.songs.shift(); + module.exports.play(queue.songs[0], message); + } + + console.error(error); + return message.channel.send( + "Erreur: {error}", { error: error.message ? error.message : error } + ); + } + queue.connection.on("disconnect", () => message.client.queue.delete(message.guild.id)); + + const dispatcher = queue.connection + .play(stream, { type: streamType }) + .on("finish", () => { + if (collector && !collector.ended) collector.stop(); + + if (queue.loop) { + // if loop is on, push the song back at the end of the queue + // so it can repeat endlessly + let lastSong = queue.songs.shift(); + queue.songs.push(lastSong); + module.exports.play(queue.songs[0], message); + } else { + // Recursively play the next song + queue.songs.shift(); + module.exports.play(queue.songs[0], message); + } + }) + .on("error", (err) => { + console.error(err); + queue.songs.shift(); + module.exports.play(queue.songs[0], message); + }); + dispatcher.setVolumeLogarithmic(queue.volume / 100); + + var date = new Date(0); + date.setSeconds(song.duration); // specify value for SECONDS here + var timeString = date.toISOString().substr(11, 8); + + try { + //let DJYT = require ("discordjs-ytdl"); + let noiceEmbed = new MessageEmbed() + .setTitle('Début de la lecture') + .attachFiles(dancingGif) + .setThumbnail('attachment://dancing.gif') + .addField('Nom', song.title, true) + .addField('Demandé par', message.author, true) + .addField('Nombre de vues', song.views, true) + .addField('Durée', timeString, true) + .setImage(song.thumbnail) + //.setImage("https://media.discordapp.net/attachments/789196713540976670/812047848047771658/lanziumbanniere.gif"); + var playingMessage = await queue.textChannel.send(noiceEmbed); + + //console.log(DJYT.thumbnail); + //`🎶 A commencé à jouer: **${song.title}** ${song.url}` + + await playingMessage.react("⏭"); + await playingMessage.react("⏯"); + await playingMessage.react("🔇"); + await playingMessage.react("🔉"); + await playingMessage.react("🔊"); + await playingMessage.react("🔁"); + await playingMessage.react("🔀"); + await playingMessage.react("⏹"); + } catch (error) { + console.error(error); + } + + const filter = (reaction, user) => user.id !== message.client.user.id; + var collector = playingMessage.createReactionCollector(filter, { + time: song.duration > 0 ? song.duration * 1000 : 600000 + }); + + collector.on("collect", (reaction, user) => { + if (!queue) return; + const member = message.guild.member(user); + + switch (reaction.emoji.name) { + case "⏭": + queue.playing = true; + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + queue.connection.dispatcher.end(); + queue.textChannel.send(`${user} ⏩ a skip la musique.`).catch(console.error).then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + collector.stop(); + break; + + case "⏯": + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + if (queue.playing) { + queue.playing = !queue.playing; + queue.connection.dispatcher.pause(true); + queue.textChannel.send(`${user} ⏸ a mis en pause la musique.`).catch(console.error).then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + } else { + queue.playing = !queue.playing; + queue.connection.dispatcher.resume(); + queue.textChannel.send(`${user} ▶ a relancé la musique!`).catch(console.error).then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + } + break; + + case "🔇": + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + if (queue.volume <= 0) { + queue.volume = 100; + queue.connection.dispatcher.setVolumeLogarithmic(100 / 100); + queue.textChannel.send(`${user} 🔊 a unmute la musique!`).catch(console.error).then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + } else { + queue.volume = 0; + queue.connection.dispatcher.setVolumeLogarithmic(0); + queue.textChannel.send(`${user} 🔇 a mute la musique!`).catch(console.error).then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + } + break; + + case "🔉": + reaction.users.remove(user).catch(console.error); + if (queue.volume == 0) return; + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + if (queue.volume - 10 <= 0) queue.volume = 0; + else queue.volume = queue.volume - 10; + queue.connection.dispatcher.setVolumeLogarithmic(queue.volume / 100); + queue.textChannel + .send(`${user} 🔉 a diminué le volume, le volume est maintenant à ${queue.volume}%`) + .catch(console.error) + .then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + break; + + case "🔊": + reaction.users.remove(user).catch(console.error); + if (queue.volume == 100) return; + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + if (queue.volume + 10 >= 100) queue.volume = 100; + else queue.volume = queue.volume + 10; + queue.connection.dispatcher.setVolumeLogarithmic(queue.volume / 100); + queue.textChannel + .send(`${user} 🔉 a augmenté le volume, le volume est maintenant à ${queue.volume}%`) + .catch(console.error) + .then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + break; + + case "🔁": + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + queue.loop = !queue.loop; + queue.textChannel + .send( + (`Le loop est maintenant ${queue.loop ? `**Actif**` : `**Inactif**`}`) + ) + .catch(console.error) + .then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + break; + + case "🔀": + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + let songs = queue.songs; + for (let i = songs.length - 1; i > 1; i--) { + let j = 1 + Math.floor(Math.random() * i); + [songs[i], songs[j]] = [songs[j], songs[i]]; + } + + queue.songs = songs; + queue.textChannel + .send( + (`Lecture aléatoire de la liste de lecture 🔀`) + ) + .catch(console.error) + .then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + break; + + case "⏹": + reaction.users.remove(user).catch(console.error); + if (!canModifyQueue(member)) return message.channel.send("Vous devez d'abord rejoindre un salon vocal !"); + queue.songs = []; + queue.textChannel.send(`${user} ⏹ a arrêté la musique!`) + .catch(console.error) + .then(msg => { + msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + }); + try { + queue.connection.dispatcher.end(); + } catch (error) { + console.error(error); + queue.connection.disconnect(); + } + collector.stop(); + break; + + default: + reaction.users.remove(user).catch(console.error); + break; + } + }); + + collector.on("end", () => { + playingMessage.reactions.removeAll().catch(console.error); + if (PRUNING && playingMessage && !playingMessage.deleted) { + playingMessage.delete({ timeout: 3000 }).catch(console.error); + } + }); + } +}; diff --git a/assets/img/8ball.png b/assets/img/8ball.png new file mode 100644 index 0000000..a8805ae Binary files /dev/null and b/assets/img/8ball.png differ diff --git a/assets/img/Music.gif b/assets/img/Music.gif new file mode 100644 index 0000000..d9a395e Binary files /dev/null and b/assets/img/Music.gif differ diff --git a/assets/img/canardcouteau.PNG b/assets/img/canardcouteau.PNG new file mode 100644 index 0000000..4ac93ae Binary files /dev/null and b/assets/img/canardcouteau.PNG differ diff --git a/assets/img/cat.gif b/assets/img/cat.gif new file mode 100644 index 0000000..144ac55 Binary files /dev/null and b/assets/img/cat.gif differ diff --git a/assets/img/choose.gif b/assets/img/choose.gif new file mode 100644 index 0000000..baef72d Binary files /dev/null and b/assets/img/choose.gif differ diff --git a/assets/img/dancing.gif b/assets/img/dancing.gif new file mode 100644 index 0000000..ceb484e Binary files /dev/null and b/assets/img/dancing.gif differ diff --git a/assets/img/divider.png b/assets/img/divider.png new file mode 100644 index 0000000..fc2645a Binary files /dev/null and b/assets/img/divider.png differ diff --git a/commands/Admin/chargement.js b/commands/Admin/chargement.js new file mode 100644 index 0000000..cf02aa6 --- /dev/null +++ b/commands/Admin/chargement.js @@ -0,0 +1,36 @@ +const { MESSAGES } = require("../../util/constants"); +const { MessageEmbed, MessageAttachment } = require("discord.js"); + +module.exports.run = async (client, message, args) => { + + const embed = new MessageEmbed() + .setAuthor(`${client.user.username} Info`, client.user.avatarURL()) + .setColor("cb4e41") + .addFields( + { name:'Configurer le prefix', value:'Faire la commande \`?config prefix (le nouveau préfix)\`', inline: true}, + { name:'\u200b', value:'\u200b', inline: true}, + { name:'\u200b', value:'\u200b', inline: true}, + ) + .setTimestamp() + .setImage("https://media.discordapp.net/attachments/789196713540976670/812047848047771658/lanziumbanniere.gif"); + + + const embed2 = new MessageEmbed() + .setColor("dc143c") + .setTitle("LanBot ") + .setDescription("LanBot a été invité !") + .setThumbnail(client.user.displayAvatarURL()) + .addFields( + { name: "Serveur ", value: `Le bot a été invité sur le serveur ${message.member.guild.name}`, inline: true}, + { name: 'Créateur du serveur', value: `L'Owner du serveur est ${message.member.guild.owner}`, inline: true}, + { name: "Invitation", value: await message.channel.createInvite({maxAge: 0, reason: "Permet au développeur de venir si besoin"}), inline: true}, + ) + .setImage(client.user.displayAvatarURL()) + .setTimestamp() + + //client.channels.cache.get('818435612678946826').send(embed2); + message.channel.send(embed) + +}; + +module.exports.help = MESSAGES.COMMANDS.ADMIN.CHARGEMENT; \ No newline at end of file diff --git a/commands/Admin/config.js b/commands/Admin/config.js new file mode 100644 index 0000000..90f4d64 --- /dev/null +++ b/commands/Admin/config.js @@ -0,0 +1,20 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args, settings) => { + const getSetting = args[0]; + const newSetting = args.slice(1).join(" "); + //const newLogSetting = args.slice(2, -1); + + switch(getSetting) { + case "prefix": { + if (newSetting) { + await client.updateGuild(message.guild, { prefix: newSetting }); + return message.channel.send(`Prefix mis à jour: \`${settings.prefix}\`-> \`${newSetting}\``); + } + message.channel.send(`Prefix actuel: \`${settings.prefix}\``); + break; + } + } +}; + +module.exports.help = MESSAGES.COMMANDS.ADMIN.CONFIG; \ No newline at end of file diff --git a/commands/Developpeur/eval.js b/commands/Developpeur/eval.js new file mode 100644 index 0000000..1ec838b --- /dev/null +++ b/commands/Developpeur/eval.js @@ -0,0 +1,17 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args) => { + function clean(text) { + if (typeof text === "string") + return text.replace(/`/g, "`" + String.fromCharCode(8203)).replace(/@/g, "@" + String.fromCharCode(8203)); + return text; + } + + if (message.author.id !== "327193195085824001") return message.channel.send("Cette commande est réservé au développeur de LanBot"); + const code = args.join(" "); + const evaled = eval(code); + const cleanCode = await clean(evaled); + message.channel.send(cleanCode, { code: "js" }); +}; + +module.exports.help = MESSAGES.COMMANDS.DEVELOPPEUR.EVAL; \ No newline at end of file diff --git a/commands/Developpeur/reload.js b/commands/Developpeur/reload.js new file mode 100644 index 0000000..d1a173e --- /dev/null +++ b/commands/Developpeur/reload.js @@ -0,0 +1,10 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args) => { + if (message.author.id !== "327193195085824001") return message.channel.send("Cette commande est réservé au développeur de LanBot"); + client.channels.cache.get('844290195787743262').send("Je redémarre !"); + await message.delete(); + + process.exit(); +}; +module.exports.help = MESSAGES.COMMANDS.DEVELOPPEUR.RELOAD; \ No newline at end of file diff --git a/commands/Informations/botinfo.js b/commands/Informations/botinfo.js new file mode 100644 index 0000000..3bf715e --- /dev/null +++ b/commands/Informations/botinfo.js @@ -0,0 +1,22 @@ +const { MessageEmbed } = require ("discord.js"); +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = (client, message, args) => { + const embed = new MessageEmbed() + .setColor("#0c2461") + .setAuthor(`${client.user.username} Info`, client.user.avatarURL()) + .addFields( + { name: 'Mémoire', value: `${(process.memoryUsage().heapUsed / 1024 /1024).toFixed(2)}MB`, inline: true}, + { name: 'Uptime', value: `${Math.floor(client.uptime / 1000 / 60).toString()} minutes`, inline: true}, + { name: '\u200b', value: `\u200b`, inline: true}, + { name: 'Serveurs', value: `${client.guilds.cache.size.toString()}`, inline: true}, + { name: 'Salons', value: `${client.channels.cache.size.toString()}`, inline: true}, + { name: 'Utilisateurs', value: `${client.guilds.cache.map(g => g.memberCount).reduce((a,b) => a + b)}`, inline: true}, + { name: 'Version', value: `Version 2.2.1`, inline: true}, + { name: 'Source', value: `[SiteWeb](https://lan7ium.fr)`, inline: true}, + { name: 'Support', value: `[Serveur Invite](https://discord.gg/K6tGTtNVTE)`, inline: true}, + ); + message.channel.send(embed); +}; + +module.exports.help = MESSAGES.COMMANDS.INFORMATIONS.BOTINFO; \ No newline at end of file diff --git a/commands/Informations/embed.txt b/commands/Informations/embed.txt new file mode 100644 index 0000000..883f60e --- /dev/null +++ b/commands/Informations/embed.txt @@ -0,0 +1,49 @@ +const { MessageEmbed } = require("discord.js"); +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = (client, message, args) => { + const embed = new MessageEmbed() + .setColor("dc143c") + .setTitle("Titre de l'embed") + .setURL("https://google.com") + .setDescription("Description de l'embed") + .setThumbnail(client.user.displayAvatarURL()) + .addField("Je suis un champ", "et je suis sa valeur") + .addFields( + { name: 'Je suis le champ 1', value: 'et je suis sa valeur', inline: true}, + { name: 'Je suis le champ 2', value: 'et en plus on est aligné', inline: true}, + ) + .setImage(client.user.displayAvatarURL()) + .setTimestamp() + .setFooter("Je suis sur le pied du footer"); + + message.channel.send(embed); +}; + +module.exports.help = MESSAGES.COMMANDS.INFORMATIONS.EMBED; + + +const embed = new MessageEmbed() + .setColor("#0c2461") + .setDescription(`Plus d'informations à propos du serveur: **${guild.name}**`) + .setThumbnail(guild.iconURL()) + .addField( + `• ID: ${guild.id} + • Owner: ${guild.owner.user.tag} (${guild.ownerID}) + • Roles: ${guild.roles.cache.size} + • Créé le: ${moment(guild.createdAt).format('DD/MM/YYYY')} + `) + .setTimestamp(); + + + const embed2 = new MessageEmbed() + .setColor("#0c2461") + .setDescription("Statistique du serveur : ") + .addFields( + { name: `Nombre de membres total : `, value: `${guild.memberCount -1 }`}, + { name: `Nombre de salons textuels : `, value: `${guild.channels.cache.filter(ch => ch.type === "text").size}`}, + { name: `Nombre de salons vocaux : `, value: `${guild.channels.cache.filter(ch => ch.type === "voice").size}`}, + ) + + message.channel.send(embed); + message.channel.send(embed2); \ No newline at end of file diff --git a/commands/Informations/serverinfo.js b/commands/Informations/serverinfo.js new file mode 100644 index 0000000..06787a7 --- /dev/null +++ b/commands/Informations/serverinfo.js @@ -0,0 +1,39 @@ +const { MessageEmbed } = require ("discord.js"); +const { MESSAGES } = require("../../util/constants"); +const moment = require("moment"); + +module.exports.run = (client, message, args) => { + const guild = message.guild; + + message.guild.members.fetch().then(fetchAll => { + + const embed = new MessageEmbed() + .setColor("#0c2461") + .setThumbnail(guild.iconURL()) + .addField(`Plus d'informations à propos du serveur : **${guild.name}**`, + `• ID: ${guild.id} + • Owner: ${guild.owner.user.tag} (${guild.ownerID}) + • Roles: ${guild.roles.cache.size} + • Créé le: ${moment(guild.createdAt).format('DD/MM/YYYY')} + ` + ) + + + const embed2 = new MessageEmbed() + .setColor("#0c2461") + .setDescription("Statistique du serveur : ") + .addFields( + { name: `Nombre de membres total : `, value: `${guild.memberCount -1 }`}, + { name: `Nombre de salons textuels : `, value: `${guild.channels.cache.filter(ch => ch.type === "text").size}`}, + { name: `Nombre de salons vocaux : `, value: `${guild.channels.cache.filter(ch => ch.type === "voice").size}`}, + { name: 'Membres Totaux', value: `${fetchAll.size}`, inline: true}, + ) + .setTimestamp(); + + message.channel.send(embed); + message.channel.send(embed2); + + }); +}; + +module.exports.help = MESSAGES.COMMANDS.INFORMATIONS.SERVERINFO; \ No newline at end of file diff --git a/commands/Informations/stats.js b/commands/Informations/stats.js new file mode 100644 index 0000000..b5bb15c --- /dev/null +++ b/commands/Informations/stats.js @@ -0,0 +1,30 @@ +const { MESSAGES } = require("../../util/constants"); +const { MessageEmbed } = require ("discord.js"); + +module.exports.run = (client, message, args) => { + const nameGuild = message.guild.name; + message.guild.members.fetch().then(fetchAll => { + const offline = fetchAll.filter(m => m.presence.status === 'offline'); + const dnd = fetchAll.filter(m => m.presence.status === 'dnd'); + const online = fetchAll.filter(m => m.presence.status === 'online'); + const bot = message.guild.members.cache.filter(member => member.user.bot).size; + + const embed = new MessageEmbed() + .setTitle("Informations sur les membres du serveur !") + .setColor("#0c2461") + .addFields( + { name: 'Nom du serveur', value: `${nameGuild}`, inline: true}, + { name: 'Membres Totaux', value: `${fetchAll.size}`, inline: true}, + { name: 'Nombre de Bots', value: `${bot}`, inline: true}, + { name: 'Membres Connectés', value: `${online.size}`, inline: true}, + { name: 'Membres Hors-ligne', value: `${offline.size}`, inline: true}, + { name: 'Membres Occupés', value: `${dnd.size}`, inline: true}, + ) + .setTimestamp(); + + message.channel.send(embed); + + }); +}; + +module.exports.help = MESSAGES.COMMANDS.INFORMATIONS.STATS; \ No newline at end of file diff --git a/commands/Informations/userinfo.js b/commands/Informations/userinfo.js new file mode 100644 index 0000000..465136e --- /dev/null +++ b/commands/Informations/userinfo.js @@ -0,0 +1,31 @@ +const { MessageEmbed } = require ("discord.js"); +const { MESSAGES } = require("../../util/constants"); +const moment = require("moment"); + +module.exports.run = (client, message, args) => { + let member = message.member; + if (args[0]) member = message.guild.member(message.mentions.users.first()); + let user = member.user; + + const embed = new MessageEmbed() + .setColor("#0c2461") + .setThumbnail(user.displayAvatarURL()) + .addField(`Plus d'informations à propos de **${user.username}**`, + `• Nom: ${user.tag} + • Bot: ${user.bot ? 'true' : 'false'} + • Crée le: ${moment(user.createdAt).format('DD/MM/YYYY | hh:mm')} + • Statut: ${user.presence.status.toUpperCase()}` + ); + + const embed2 = new MessageEmbed() + .setColor("#0c2461") + .addField(`L'utilisateur **${user.username}** ${member.username === undefined ? '' : `aka **${member.username}**`}`, + `• A rejoint le serveur le: ${moment(member.joinedAt).format('DD/MM/YYYY | hh:mm')} + • Ce membre possède les rôles suivants : ${member.roles.cache.map(roles => `\`${roles.name}\``).join(', ')}` + ); + + message.channel.send(embed); + message.channel.send(embed2); +}; + +module.exports.help = MESSAGES.COMMANDS.INFORMATIONS.USERINFO; \ No newline at end of file diff --git a/commands/Musique/join.js b/commands/Musique/join.js new file mode 100644 index 0000000..be3df8d --- /dev/null +++ b/commands/Musique/join.js @@ -0,0 +1,18 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args, settings) => { + const { channel } = message.member.voice; + + const queueConstruct = { + textChannel: message.channel, + channel, + connection: null, + songs: [], + loop: false, + playing: true + }; + + queueConstruct.connection = await channel.join(); +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.JOIN; \ No newline at end of file diff --git a/commands/Musique/leave.js b/commands/Musique/leave.js new file mode 100644 index 0000000..e038e4b --- /dev/null +++ b/commands/Musique/leave.js @@ -0,0 +1,8 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = (client, message, args, settings) => { + const queue = message.client.queue.get(message.guild.id); + queue.connection.disconnect() +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.LEAVE; \ No newline at end of file diff --git a/commands/Musique/loop.js b/commands/Musique/loop.js new file mode 100644 index 0000000..ee222fb --- /dev/null +++ b/commands/Musique/loop.js @@ -0,0 +1,26 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + + +module.exports.run = (client, message, args, settings) => { + + if (!canModifyQueue(message.member)) return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + const queue = message.client.queue.get(message.guild.id) + if(!queue){ return message.channel.send({ + embed: { + description: `Liste d'attente vide ! merci d'utiliser la commande \`${settings.prefix}play + URL / Nom de la musique\` !`, + color: 'BLACK' + } + }) + } + + // toggle from false to true and reverse + queue.loop = !queue.loop; + //queue.connection.dispatcher.loop() + return message.channel.send(`Le loop est maintenant ${queue.loop ? `**Actif**` : `**Inactif**`}`) + + + +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.LOOP; \ No newline at end of file diff --git a/commands/Musique/lyrics.js b/commands/Musique/lyrics.js new file mode 100644 index 0000000..0cea787 --- /dev/null +++ b/commands/Musique/lyrics.js @@ -0,0 +1,30 @@ +const { MessageEmbed } = require("discord.js"); +const lyricsFinder = require("lyrics-finder"); +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args, settings) => { + const queue = message.client.queue.get(message.guild.id); + if (!queue) return message.channel.send("Aucune musique lancé !").catch(console.error); + + let lyrics = null; + const title = queue.songs[0].title; + + try { + lyrics = await lyricsFinder(queue.songs[0].title, ""); + if (!lyrics) lyrics = `Pas de paroles trouvé pour ${queue.songs[0].title} ! `; + } catch (error) { + lyrics = `Pas de paroles trouvé pour ${queue.songs[0].title} ! `; + } + + let lyricsEmbed = new MessageEmbed() + .setTitle(`Paroles pour ${queue.songs[0].title}`) + .setDescription(lyrics) + .setColor("GREEN") + .setTimestamp(); + + if (lyricsEmbed.description.length >= 2048) + lyricsEmbed.description = `${lyricsEmbed.description.substr(0, 2045)}...`; + return message.channel.send(lyricsEmbed).catch(console.error); +} + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.LYRICS; diff --git a/commands/Musique/move.js b/commands/Musique/move.js new file mode 100644 index 0000000..f8e8ae2 --- /dev/null +++ b/commands/Musique/move.js @@ -0,0 +1,22 @@ +const { MESSAGES } = require("../../util/constants"); +const move = require("array-move"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + const queue = message.client.queue.get(message.guild.id); + if (!queue) return message.channel.send("Il n'y a pas de musique dans la file d'attente.").catch(console.error); + if (!canModifyQueue(message.member)) return; + + let song = queue.songs[args[0] - 1]; + + queue.songs = move(queue.songs, args[0] - 1, args[1] == 1 ? 1 : args[1] - 1); + queue.textChannel.send( + ("Déplacement effectué !", { + author: message.author, + title: song.title, + index: args[1] == 1 ? 1 : args[1] + }) + ); +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.MOVE; diff --git a/commands/Musique/nowplaying.js b/commands/Musique/nowplaying.js new file mode 100644 index 0000000..bd89131 --- /dev/null +++ b/commands/Musique/nowplaying.js @@ -0,0 +1,52 @@ +const { MessageEmbed, MessageAttachment } = require("discord.js"); +const musicGif = new MessageAttachment('./assets/img/Music.gif'); +const { MESSAGES } = require("../../util/constants"); +const createBar = require("string-progressbar"); + +module.exports.run = (client, message, args, settings) => { + const channel = message.member.voice.channel; + if (!channel) return message.channel.send('Tu dois te trouver dans un salon vocal pour utiliser cette commande'); + let queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send({ + embed:{ + title: `Aucune musique n'est lancé actuellement donc merci d'utiliser la commande \`${settings.prefix}play + URL\`! ` + } + }) + + const song = queue.songs[0]; + const seek = (queue.connection.dispatcher.streamTime - queue.connection.dispatcher.pausedTime) / 1000; + const left = song.duration - seek; + + let nowPlaying = new MessageEmbed() + .setTitle("En lecture") + .setDescription(`${song.title}\n${song.url}`) + .setColor("#F8AA2A") + .setAuthor(message.client.user.username) + //.attachFiles(musicGif) + //.setThumbnail('attachment://Music.gif') + .setThumbnail('https://tenor.com/8P2l.gif'); + + + var time = new Date(left * 1000).toISOString().substr(11, 8); + + if (song.duration > 0) { + nowPlaying.addField( + "\u200b", + new Date(seek * 1000).toISOString().substr(11, 8) + + "[" + + createBar(song.duration == 0 ? seek : song.duration, seek, 20)[0] + + "]" + + (song.duration == 0 ? " ◉ LIVE" : new Date(song.duration * 1000).toISOString().substr(11, 8)), + false + ); + nowPlaying.setFooter( + (`Temps restant : ${time}`) + ); + } + + return message.channel.send(nowPlaying); + +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.NOWPLAYING; + diff --git a/commands/Musique/pause.js b/commands/Musique/pause.js new file mode 100644 index 0000000..073cbf5 --- /dev/null +++ b/commands/Musique/pause.js @@ -0,0 +1,19 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + let queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send({ + embed: { + description: "Impossible de mettre en pause, car aucune musique n'est lancé !" + } + }) + if(queue.playing !== false) + queue.connection.dispatcher.pause() + message.react('⏸') + message.channel.send('Musique mis en pause !') +} + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.PAUSE; \ No newline at end of file diff --git a/commands/Musique/play.js b/commands/Musique/play.js new file mode 100644 index 0000000..65a93b0 --- /dev/null +++ b/commands/Musique/play.js @@ -0,0 +1,116 @@ +const { play } = require("../../Includes/play"); +const ytdl = require("ytdl-core"); +const YouTubeAPI = require("simple-youtube-api"); +const { YOUTUBE_API_KEY, DEFAULT_VOLUME } = require("../../util/LanBot"); +const youtube = new YouTubeAPI(YOUTUBE_API_KEY); +const { MessageEmbed } = require("discord.js"); + + + +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args, settings) => { + const { channel } = message.member.voice; + + const serverQueue = message.client.queue.get(message.guild.id); + if (!channel) return message.reply("Vous devez d'abord rejoindre un canal vocal!").catch(console.error); + if (serverQueue && channel !== message.guild.me.voice.channel) + return message + .reply("Vous devez être dans le même canal que {user}", { user: message.client.user }) + .catch(console.error); + + if (!channel.permissionsFor(message.client.user).has("CONNECT")) return message.channel.send("Je n'ai pas la permission de rejoindre un salon vocal !") + if (!channel.permissionsFor(message.client.user).has("SPEAK"))return message.channel.send("Je n'ai pas la permission Parler dans le salon vocal !") + + const search = args.join(" "); + const videoPattern = /^(https?:\/\/)?(www\.)?(m\.)?(youtube\.com|youtu\.?be)\/.+$/gi; + const playlistPattern = /^.*(list=)([^#\&\?]*).*/gi; + const url = args[0]; + const urlValid = videoPattern.test(args[0]); + + // Start the playlist if playlist url was provided + if (!videoPattern.test(args[0]) && playlistPattern.test(args[0])) { + return message.client.commands.get("playlist").execute(message, args); + }; + + + const queueConstruct = { + textChannel: message.channel, + channel, + connection: null, + songs: [], + loop: false, + volume: DEFAULT_VOLUME || 100, + playing: true + }; + + let songInfo = null; + let song = null; + + if (urlValid) { + try { + songInfo = await ytdl.getInfo(url); + song = { + title: songInfo.videoDetails.title, + url: songInfo.videoDetails.video_url, + duration: songInfo.videoDetails.lengthSeconds, + views: songInfo.videoDetails.viewCount, + thumbnail: songInfo.videoDetails.thumbnails[2]["url"] + }; + } catch (error) { + console.error(error); + return message.reply(error.message).catch(console.error); + } + } else { + try { + const results = await youtube.searchVideos(search, 1, { part: "snippet" }); + songInfo = await ytdl.getInfo(results[0].url); + song = { + title: songInfo.videoDetails.title, + url: songInfo.videoDetails.video_url, + duration: songInfo.videoDetails.lengthSeconds, + views: songInfo.videoDetails.viewCount, + thumbnail: songInfo.videoDetails.thumbnails[2]["url"] + }; + } catch (error) { + console.error(error); + return message.reply(error.message).catch(console.error); + } + } + var date = new Date(0); + date.setSeconds(song.duration); // specify value for SECONDS here + var timeString = date.toISOString().substr(11, 8); + + + if (serverQueue) { + serverQueue.songs.push(song); + let embed = new MessageEmbed() + .setTitle('Ajouté à la liste de lecture!') + .setColor('#00fff1') + .addField('Nom', song.title, true) + .setThumbnail(song.thumbnail) + .addField('Nombre de vues', song.views, true) + .addField('Demandé par', message.author, true) + .addField('Durée', timeString, true) + return serverQueue.textChannel + .send(embed) + .catch(console.error); + } + + queueConstruct.songs.push(song); + message.client.queue.set(message.guild.id, queueConstruct); + + try { + queueConstruct.connection = await channel.join(); + await queueConstruct.connection.voice.setSelfDeaf(true); + play(queueConstruct.songs[0], message); + } catch (error) { + console.error(error); + message.client.queue.delete(message.guild.id); + await channel.leave(); + return message.channel.send(`Impossible de rejoindre le channel: ${error}`).catch(console.error); + } + }; + + module.exports.help = MESSAGES.COMMANDS.MUSIQUE.PLAY; + diff --git a/commands/Musique/playlist.js b/commands/Musique/playlist.js new file mode 100644 index 0000000..f93a356 --- /dev/null +++ b/commands/Musique/playlist.js @@ -0,0 +1,114 @@ +const { MESSAGES } = require("../../util/constants"); +const { MessageEmbed } = require("discord.js"); +const { play } = require("../../Includes/play"); +const YouTubeAPI = require("simple-youtube-api"); + +const { + YOUTUBE_API_KEY, + MAX_PLAYLIST_SIZE, + DEFAULT_VOLUME, +} = require("../../util/LanBot"); +const youtube = new YouTubeAPI(YOUTUBE_API_KEY); + + +module.exports.run = async (client, message, args, settings) => { + const { channel } = message.member.voice; + const serverQueue = message.client.queue.get(message.guild.id); + + if (!channel.permissionsFor(message.client.user).has("CONNECT")) return message.channel.send("Je n'ai pas la permission de rejoindre un salon vocal !") + if (!channel.permissionsFor(message.client.user).has("SPEAK"))return message.channel.send("Je n'ai pas la permission Parler dans le salon vocal !") + + if (serverQueue && channel !== message.guild.me.voice.channel) + return message + .reply(`Vous devez être dans le même canal que ${message.client.user}`) + .catch(console.error); + + const search = args.join(" "); + const pattern = /^.*(youtu.be\/|list=)([^#\&\?]*).*/gi; + const url = args[0]; + const urlValid = pattern.test(args[0]); + + const queueConstruct = { + textChannel: message.channel, + channel, + connection: null, + songs: [], + loop: false, + volume: DEFAULT_VOLUME || 100, + playing: true + }; + + let playlist = null; + let videos = []; + + if (urlValid) { + try { + playlist = await youtube.getPlaylist(url, { part: "snippet" }); + videos = await playlist.getVideos(MAX_PLAYLIST_SIZE || 10, { part: "snippet" }); + } catch (error) { + console.error(error); + return message.reply("Playlist introuvable ! 🥺 ").catch(console.error); + } + } else { + try { + const results = await youtube.searchPlaylists(search, 1, { part: "snippet" }); + playlist = results[0]; + videos = await playlist.getVideos(MAX_PLAYLIST_SIZE || 10, { part: "snippet" }); + } catch (error) { + console.error(error); + return message.reply(error.message).catch(console.error); + } + } + + const newSongs = videos + .filter((video) => video.title != "Private video" && video.title != "Deleted video") + .map((video) => { + return (song = { + title: video.title, + url: video.url, + duration: video.durationSeconds + }); + }); + + serverQueue ? serverQueue.songs.push(...newSongs) : queueConstruct.songs.push(...newSongs); + + let playlistEmbed = new MessageEmbed() + .setTitle(`${playlist.title}`) + .setDescription(newSongs.map((song, index) => `${index + 1}. ${song.title}`)) + .setURL(playlist.url) + .setColor("#F8AA2A") + .setTimestamp(); + + if (playlistEmbed.description.length >= 2048) + playlistEmbed.description = + playlistEmbed.description.substr(0, 2007) + ("\nListe de lecture supérieure à la limite de caractères..."); + + message.channel.send((`${message.author} a commencé une playlist`), playlistEmbed); + + if (!serverQueue) { + message.client.queue.set(message.guild.id, queueConstruct); + + try { + queueConstruct.connection = await channel.join(); + await queueConstruct.connection.voice.setSelfDeaf(true); + play(queueConstruct.songs[0], message); + } catch (error) { + console.error(error); + message.client.queue.delete(message.guild.id); + await channel.leave(); + return message.channel.send(`Impossible de rejoindre le channel: ${error}`).catch(console.error); + } + } +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.PLAYLIST; + +/* +Play Pause ⏯️ +Stop ⏹️ +Shuffle 🔀 +Loop All 🔁 +Loop One 🔂 + +*/ + diff --git a/commands/Musique/pruning.js b/commands/Musique/pruning.js new file mode 100644 index 0000000..50d43bc --- /dev/null +++ b/commands/Musique/pruning.js @@ -0,0 +1,28 @@ +const fs = require("fs"); +const { MESSAGES } = require("../../util/constants"); + +let config; + +try { + config = require("../../config"); +} catch (error) { + config = null; +} + +module.exports.run = (client, message, args, settings) => { + if (!config) return; + config.PRUNING = !config.PRUNING; + + fs.writeFile("../../config", JSON.stringify(config, null, 2), (err) => { + if (err) { + console.log(err); + return message.channel.send("Une erreur s'est produite lors de l'écriture dans le fichier.").catch(console.error); + } + + return message.channel + .send(`Pruning est ${config.PRUNING ? "**ON**" : "**OFF**"}`) + .catch(console.error); + }); +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.PRUNING; \ No newline at end of file diff --git a/commands/Musique/queue.js b/commands/Musique/queue.js new file mode 100644 index 0000000..d0171d8 --- /dev/null +++ b/commands/Musique/queue.js @@ -0,0 +1,88 @@ +const { MessageEmbed } = require('discord.js') +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args, settings) => { + const permissions = message.channel.permissionsFor(message.client.user); + if (!permissions.has(["MANAGE_MESSAGES", "ADD_REACTIONS"])) + return message.reply("Il me manque l'autorisation de gérer les messages ou d'ajouter des réactions"); + + const queue = message.client.queue.get(message.guild.id); + if (!queue) return message.channel.send("❌ **Rien ne joue sur ce serveur**"); + + let currentPage = 0; + const embeds = generateQueueEmbed(message, queue.songs); + + const queueEmbed = await message.channel.send( + `**${("Page actuelle - ")} ${currentPage + 1}/${embeds.length}**`, + embeds[currentPage] + ); + + try { + await queueEmbed.react("⬅️"); + await queueEmbed.react("⏹"); + await queueEmbed.react("➡️"); + } catch (error) { + console.error(error); + message.channel.send(error.message).catch(console.error); + } + + const filter = (reaction, user) => + ["⬅️", "⏹", "➡️"].includes(reaction.emoji.name) && message.author.id === user.id; + const collector = queueEmbed.createReactionCollector(filter, { time: 60000 }); + + collector.on("collect", async (reaction, user) => { + try { + if (reaction.emoji.name === "➡️") { + if (currentPage < embeds.length - 1) { + currentPage++; + queueEmbed.edit( + ("Page actuelle - ", { page: currentPage + 1, length: embeds.length }), + embeds[currentPage] + ); + } + } else if (reaction.emoji.name === "⬅️") { + if (currentPage !== 0) { + --currentPage; + queueEmbed.edit( + ("Page actuelle - ", { page: currentPage + 1, length: embeds.length }), + embeds[currentPage] + ); + } + } else { + collector.stop(); + reaction.message.reactions.removeAll(); + } + await reaction.users.remove(message.author.id); + } catch (error) { + console.error(error); + return message.channel.send(error.message).catch(console.error); + } + }); +} + +function generateQueueEmbed(message, queue) { + let embeds = []; + let k = 10; + + for (let i = 0; i < queue.length; i += 10) { + const current = queue.slice(i, k); + let j = i; + k += 10; + + const info = current.map((track) => `${++j} - [${track.title}](${track.url})`).join("\n"); + + const embed = new MessageEmbed() + .setTitle("Song Queue\n") + .setThumbnail(message.guild.iconURL()) + .setColor("#F8AA2A") + .setDescription( + (`**Morceau en cours - [${queue[0].title}](${queue[0].url})**\n\n${info}`) + ) + .setTimestamp(); + embeds.push(embed); + } + + return embeds; + } + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.QUEUE; \ No newline at end of file diff --git a/commands/Musique/radiozebre.js b/commands/Musique/radiozebre.js new file mode 100644 index 0000000..f3a2f8c --- /dev/null +++ b/commands/Musique/radiozebre.js @@ -0,0 +1,104 @@ +const { MESSAGES } = require("../../util/constants"); +const { MessageEmbed } = require("discord.js"); +const { play } = require("../../Includes/play"); +const YouTubeAPI = require("simple-youtube-api"); + +const { + YOUTUBE_API_KEY, + MAX_PLAYLIST_SIZE, + DEFAULT_VOLUME, +} = require("../../util/LanBot"); +const youtube = new YouTubeAPI(YOUTUBE_API_KEY); + + +module.exports.run = async (client, message, args, settings) => { + const { channel } = message.member.voice; + const serverQueue = message.client.queue.get(message.guild.id); + + if (!channel.permissionsFor(message.client.user).has("CONNECT")) return message.channel.send("Je n'ai pas la permission de rejoindre un salon vocal !") + if (!channel.permissionsFor(message.client.user).has("SPEAK"))return message.channel.send("Je n'ai pas la permission Parler dans le salon vocal !") + + if (serverQueue && channel !== message.guild.me.voice.channel) + return message + .reply(`Vous devez être dans le même canal que ${message.client.user}`) + .catch(console.error); + + const search = ("https://youtube.com/playlist?list=PLEQIc8j7Pa4SX6ixC2D6wplqzXI9Jv6el"); + const pattern = /^.*(youtu.be\/|list=)([^#\&\?]*).*/gi; + const url = ("https://youtube.com/playlist?list=PLEQIc8j7Pa4SX6ixC2D6wplqzXI9Jv6el"); + const urlValid = pattern.test("https://youtube.com/playlist?list=PLEQIc8j7Pa4SX6ixC2D6wplqzXI9Jv6el"); + + const queueConstruct = { + textChannel: message.channel, + channel, + connection: null, + songs: [], + loop: false, + volume: DEFAULT_VOLUME || 100, + playing: true + }; + + let playlist = null; + let videos = []; + + if (urlValid) { + try { + playlist = await youtube.getPlaylist(url, { part: "snippet" }); + videos = await playlist.getVideos(MAX_PLAYLIST_SIZE || 10, { part: "snippet" }); + } catch (error) { + console.error(error); + return message.reply("Playlist introuvable ! 🥺 ").catch(console.error); + } + } else { + try { + const results = await youtube.searchPlaylists(search, 1, { part: "snippet" }); + playlist = results[0]; + videos = await playlist.getVideos(MAX_PLAYLIST_SIZE || 10, { part: "snippet" }); + } catch (error) { + console.error(error); + return message.reply(error.message).catch(console.error); + } + } + + const newSongs = videos + .filter((video) => video.title != "Private video" && video.title != "Deleted video") + .map((video) => { + return (song = { + title: video.title, + url: video.url, + duration: video.durationSeconds + }); + }); + + serverQueue ? serverQueue.songs.push(...newSongs) : queueConstruct.songs.push(...newSongs); + + let playlistEmbed = new MessageEmbed() + .setTitle(`${playlist.title}`) + .setDescription(newSongs.map((song, index) => `${index + 1}. ${song.title}`)) + .setURL(playlist.url) + .setColor("#F8AA2A") + .setTimestamp(); + + if (playlistEmbed.description.length >= 2048) + playlistEmbed.description = + playlistEmbed.description.substr(0, 2007) + ("\nListe de lecture supérieure à la limite de caractères..."); + + message.channel.send((`${message.author} a commencé une playlist`), playlistEmbed); + + if (!serverQueue) { + message.client.queue.set(message.guild.id, queueConstruct); + + try { + queueConstruct.connection = await channel.join(); + await queueConstruct.connection.voice.setSelfDeaf(true); + play(queueConstruct.songs[0], message); + } catch (error) { + console.error(error); + message.client.queue.delete(message.guild.id); + await channel.leave(); + return message.channel.send(`Impossible de rejoindre le channel: ${error}`).catch(console.error); + } + } +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.RADIOZEBRE; diff --git a/commands/Musique/remove.js b/commands/Musique/remove.js new file mode 100644 index 0000000..e8736ab --- /dev/null +++ b/commands/Musique/remove.js @@ -0,0 +1,33 @@ +const pattern = /^[0-9]{1,2}(\s*,\s*[0-9]{1,2})*$/; +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + const queue = message.client.queue.get(message.guild.id); + + if (!queue) return message.channel.send("Il n'y a pas de file d'attente.").catch(console.error); + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + + const arguments = args.join(""); + const songs = arguments.split(",").map((arg) => parseInt(arg)); + let removed = []; + + if (pattern.test(arguments)) { + queue.songs = queue.songs.filter((item, index) => { + if (songs.find((songIndex) => songIndex - 1 === index)) removed.push(item); + else return true; + }); + + queue.textChannel.send( + `${message.author} ❌ suppression de **${removed.map((song) => song.title).join("\n")}** de la file d'attente.` + ); + } else if (!isNaN(args[0]) && args[0] >= 1 && args[0] <= queue.songs.length) { + console.log("On a eu de la chance !"); + return queue.textChannel.send( + `${message.author} ❌ suppression de **${queue.songs.splice(args[0] - 1, 1)[0].title}** de la file d'attente.` + ); + } + }; + + module.exports.help = MESSAGES.COMMANDS.MUSIQUE.REMOVE; \ No newline at end of file diff --git a/commands/Musique/resume.js b/commands/Musique/resume.js new file mode 100644 index 0000000..4ba157b --- /dev/null +++ b/commands/Musique/resume.js @@ -0,0 +1,18 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + let queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send({ + embed: { + description: "Aucune musique actuellement en pause !" + } + }) + if(queue.playing !== false) + queue.connection.dispatcher.resume() + message.react('▶') + message.channel.send('Musique relancée !') +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.RESUME; \ No newline at end of file diff --git a/commands/Musique/search.js b/commands/Musique/search.js new file mode 100644 index 0000000..ae1e667 --- /dev/null +++ b/commands/Musique/search.js @@ -0,0 +1,60 @@ +const { MessageEmbed } = require("discord.js"); +const YouTubeAPI = require("simple-youtube-api"); +const { YOUTUBE_API_KEY } = require("../../util/LanBot"); +const youtube = new YouTubeAPI(YOUTUBE_API_KEY); +const { MESSAGES } = require("../../util/constants"); + + +module.exports.run = async (client, message, args, settings) => { + + + if (message.channel.activeCollector) return message.reply("Un collecteur de messages est déjà actif dans ce canal."); + if (!message.member.voice.channel) + return message.reply("Vous devez d'abord rejoindre un canal vocal!").catch(console.error); + + const search = args.join(" "); + + let resultsEmbed = new MessageEmbed() + .setTitle("**Répondez avec le numéro de la chanson que vous souhaitez écouter**") + .setDescription(`Résultat pour: ${search}`) + .setColor("#F8AA2A"); + + try { + const results = await youtube.searchVideos(search, 10); + results.map((video, index) => resultsEmbed.addField(video.shortURL, `${index + 1}. ${video.title}`)); + + let resultsMessage = await message.channel.send(resultsEmbed); + + function filter(msg) { + const pattern = /^[0-9]{1,2}(\s*,\s*[0-9]{1,2})*$/; + return pattern.test(msg.content); + } + + message.channel.activeCollector = true; + const response = await message.channel.awaitMessages(filter, { max: 1, time: 30000, errors: ["time"] }); + const reply = response.first().content; + + if (reply.includes(",")) { + let songs = reply.split(",").map((str) => str.trim()); + + for (let song of songs) { + await message.client.commands + .get("play") + .execute(message, [resultsEmbed.fields[parseInt(song) - 1].name]); + } + } else { + const choice = resultsEmbed.fields[parseInt(response.first()) - 1].name; + message.client.commands.get("play").execute(message, [choice]); + } + + message.channel.activeCollector = false; + resultsMessage.delete().catch(console.error); + response.first().delete().catch(console.error); + } catch (error) { + console.error(error); + message.channel.activeCollector = false; + message.reply("lantium a encore chié sur le code ! ").catch(console.error); + } + } + + module.exports.help = MESSAGES.COMMANDS.MUSIQUE.SEARCH; diff --git a/commands/Musique/shuffle.js b/commands/Musique/shuffle.js new file mode 100644 index 0000000..0e7872d --- /dev/null +++ b/commands/Musique/shuffle.js @@ -0,0 +1,23 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + const queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send("Aucune musique dans la liste d'attente !") + + let songs = queue.songs; + for (let i = songs.length - 1; i > 1; i--) { + let j = 1 + Math.floor(Math.random() * i); + [songs[i], songs[j]] = [songs[j], songs[i]]; + } + + queue.songs = songs; + + message.client.queue.set(message.guild.id, queue); + message.channel.send(`Lecture aléatoire de la liste de lecture 🔀`).catch(console.error); +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.SHUFFLE; diff --git a/commands/Musique/skip.js b/commands/Musique/skip.js new file mode 100644 index 0000000..e18fceb --- /dev/null +++ b/commands/Musique/skip.js @@ -0,0 +1,23 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + let queue = message.client.queue.get(message.guild.id) + if(!queue){ return message.channel.send({ + embed: { + description: `Liste d'attente vide ! merci d'utiliser la commande \`${settings.prefix}play + URL / Nom de la musique\` !`, + color: 'BLACK' + } + }) +} + if(queue.songs.length !== 0) { + message.react('✅') + queue.connection.dispatcher.end('Dacodac Je passe à la suivante') + } + +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.SKIP; \ No newline at end of file diff --git a/commands/Musique/skipto.js b/commands/Musique/skipto.js new file mode 100644 index 0000000..a608396 --- /dev/null +++ b/commands/Musique/skipto.js @@ -0,0 +1,33 @@ + +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + + + const queue = message.client.queue.get(message.guild.id); + if (!queue) return message.channel.send("Il n'y a pas de file d'attente.").catch(console.error); + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + if (args[0] > queue.songs.length) + return message + .reply(`La file d'attente contient seulement ${queue.songs.length} chansons!`) + .catch(console.error); + + queue.playing = true; + + if (queue.loop) { + for (let i = 0; i < args[0] - 2; i++) { + queue.songs.push(queue.songs.shift()); + } + } else { + queue.songs = queue.songs.slice(args[0] - 2); + } + + queue.connection.dispatcher.end(); + queue.textChannel + .send(`${message.author} ⏭ skip ${args[0] - 1} musiques`) + .catch(console.error); + } + + module.exports.help = MESSAGES.COMMANDS.MUSIQUE.SKIPTO; diff --git a/commands/Musique/stop.js b/commands/Musique/stop.js new file mode 100644 index 0000000..d6575f2 --- /dev/null +++ b/commands/Musique/stop.js @@ -0,0 +1,19 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + let queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send({ + embed: { + description: "Aucune musique de jouer, donc impossible d'utiliser la commande !", + color: 'BLACK' + } + }) + message.react('✅') + queue.songs = [] + queue.connection.dispatcher.end('Fin!') +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.STOP; \ No newline at end of file diff --git a/commands/Musique/volume.js b/commands/Musique/volume.js new file mode 100644 index 0000000..8059b9c --- /dev/null +++ b/commands/Musique/volume.js @@ -0,0 +1,22 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + const queue = message.client.queue.get(message.guild.id); + + if (!queue) return message.reply(i18n.__("volume.errorNotQueue")).catch(console.error); + if (!canModifyQueue(message.member))return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !'); + + + if (!args[0]) return message.reply(`🔊 Le volume actuelle est de: **${queue.volume}%**`).catch(console.error); + if (isNaN(args[0])) return message.reply("Veuillez utiliser un nombre pour régler le volume.").catch(console.error); + if (Number(args[0]) > 100 || Number(args[0]) < 0) + return message.reply("Veuillez utiliser un nombre compris entre 0 et 100.").catch(console.error); + + queue.volume = args[0]; + queue.connection.dispatcher.setVolumeLogarithmic(args[0] / 100); + return queue.textChannel.send(`Volume réglé sur: **${args[0]}%**`).catch(console.error); + +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.VOLUME; \ No newline at end of file diff --git a/commands/Utilitaire/help.js b/commands/Utilitaire/help.js new file mode 100644 index 0000000..30483d1 --- /dev/null +++ b/commands/Utilitaire/help.js @@ -0,0 +1,68 @@ +const { MESSAGES } = require("../../util/constants"); +const { MessageEmbed } = require("discord.js"); +const { readdirSync } = require("fs"); +const categoryList = readdirSync('./commands'); + +module.exports.run = (client, message, args, settings) => { + + //let user = message.guild.member(message.mentions.users.first()); + message.delete(); + + if(!args.length) { + const embedIntro = new MessageEmbed() + .setAuthor('Liste des categories', message.guild.iconURL()) + .setColor('#0c76e7') + .setDescription(`Voici la liste des catégories.\nPour plus d'information, merci de faire la commande \`${settings.prefix}help \` ou \`${settings.prefix}help \``) + .setTimestamp(new Date()) + message.channel.send(embedIntro) + // message.member.send("**Les commandes sont à taper dans le serveur et pas en MP désolé** :innocent: ") + // message.channel.send(embedIntro); + // message.channel.send("Regarde tes MP :wink:").then(msg => { + // msg.delete({ timeout: 5000 /*time unitl delete in milliseconds*/}); + // }) + + const embedCat = new MessageEmbed() + .setColor('#0c76e7') + .setAuthor('Help', client.user.displayAvatarURL()) + .setFooter('Help', client.user.displayAvatarURL()) + .setTimestamp(new Date()) + .addField('Voici les différentes catégories de LanBot', `**${categoryList.join('\n')}**`) + message.channel.send(embedCat); + } else if(categoryList.includes(args[0])) { + const embed = new MessageEmbed() + .setColor('#0c76e7') + .setDescription(`Voici la liste des commandes de cette catégorie.\nPour plus d'informations, \`${settings.prefix}help \``) + .setAuthor(args[0], client.user.displayAvatarURL()) + .setFooter(args[0], client.user.displayAvatarURL()) + .setTimestamp(new Date()) + .addField(`Pas assez de commande ? Envie d'en avoir plus ?`, `Fait la commande \`${settings.prefix}sugg\` pour faire ta suggestion au développeur :blush:`) + + const cmds = client.commands.filter(cmd => cmd.help.category=== args[0].toLowerCase()).array(); + cmds.forEach(cmd => { + + const aliases = (!cmd.help.aliases)? 'aucun':cmd.help.aliases.join(', '); + embed.addField(`${settings.prefix}${cmd.help.name}`, `Description: ${cmd.help.description}\nAliase(s): ${aliases}\nUtilisation(s): ${settings.prefix}${cmd.help.usage.join('\n')}`); + + }); + + message.channel.send(embed); + + } else { + const command = client.commands.find(cmd => cmd.help.name === args[0]); + if(!command) return message.channel.send('Commande ou Catégorie invalide !') + const aliases = (!command.help.aliases)? 'aucun':command.help.aliases.join('\n'); + + const embed = new MessageEmbed() + .setColor('#0c76e7') + .setAuthor(args[0], client.user.displayAvatarURL()) + .setFooter(args[0], client.user.displayAvatarURL()) + .setTimestamp(new Date()) + .addField(`${settings.prefix}${command.help.name}`, `Description: ${command.help.description}\nAliase(s): ${aliases}\nUtilisation(s): ${settings.prefix}${command.help.usage.join('\n')}`); + + message.channel.send(embed); + + } + +}; + +module.exports.help = MESSAGES.COMMANDS.UTILITAIRE.HELP; \ No newline at end of file diff --git a/commands/Utilitaire/ping.js b/commands/Utilitaire/ping.js new file mode 100644 index 0000000..0f33856 --- /dev/null +++ b/commands/Utilitaire/ping.js @@ -0,0 +1,12 @@ +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = async (client, message, args) => { + const msg = await message.channel.send("Pong ! "); + msg.edit( + `Pong ! + Latence du bot: ${msg.createdTimestamp - message.createdTimestamp}ms + Latence de l'API: ${Math.round(client.ws.ping)}ms` + ) +}; + +module.exports.help = MESSAGES.COMMANDS.UTILITAIRE.PING; \ No newline at end of file diff --git a/commands/Utilitaire/yt.js b/commands/Utilitaire/yt.js new file mode 100644 index 0000000..b69d7d3 --- /dev/null +++ b/commands/Utilitaire/yt.js @@ -0,0 +1,15 @@ +const { MESSAGES } = require("../../util/constants"); +const { DiscordTogether } = require('discord-together'); + +module.exports.run = (client, message, args, settings) => { + + client.discordTogether = new DiscordTogether(client); + + if(message.member.voice.channel) { + client.discordTogether.createTogetherCode(message.member.voice.channel.id, 'youtube').then(async invite => { + return message.channel.send(`${invite.code} \nRemarque : vous devez cliquer sur le LIEN BLEU, et non sur le bouton 'Play', afin de démarrer l'activité !`); + }); + }; + }; + +module.exports.help = MESSAGES.COMMANDS.UTILITAIRE.YT; \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..d9e21d7 --- /dev/null +++ b/config.js @@ -0,0 +1,12 @@ +module.exports = { + TOKEN: "", + DBCONNECTION: '', + YOUTUBE_API_KEY: "", + MAX_PLAYLIST_SIZE: 200, + PRUNING: true, + STAY_TIME: 30, + DEFAULT_VOLUME: 80, + DEFAULTSETTINGS: { + prefix: "?", + } +} diff --git a/events/client/ready.js b/events/client/ready.js new file mode 100644 index 0000000..ee57f7d --- /dev/null +++ b/events/client/ready.js @@ -0,0 +1,14 @@ + + +module.exports = client => { + + console.log(`${client.user.tag} oberve les ${client.guilds.cache.map(g => g.memberCount).reduce((a,b) => a + b)} utilisateur du serveur !`) + //client.channels.cache.get('818435944968618006').send("Le bot est prêt !"); + + let activites = ['Créer par Lantium !',`Ecoute prefix + help` ], i = 0; + +// let activites = ['Jour spécial pour Lantium ! 🎂'], i = 0; + + setInterval(() => client.user.setPresence({ activity: { name: `${activites [i++ % activites.length]}`, type: 'PLAYING' }, status: 'online' }), 5000); + +} diff --git a/events/guild/guildCreate.js b/events/guild/guildCreate.js new file mode 100644 index 0000000..cf12934 --- /dev/null +++ b/events/guild/guildCreate.js @@ -0,0 +1,26 @@ +const { MessageEmbed } = require("discord.js"); + +module.exports = async (client, guild, message) => { + const newGuild = { + guildID: guild.id, + guildName: guild.name + }; + + await client.createGuild(newGuild); + + const flag = guild.systemChannel; + + //const msg = ("Bonjour, je m'appelle LanBot\nJe suis content que vous m'ayez choisi pour vous assister dans votre serveur et je me ferai une joie de mettre mes commandes et ma puissance de calcul à votre contribution.\n\nJe vous laisse le plaisir de faire la commande \`?init\` pour m'initialiser et suivre mes indications !\n\nSi vous avez le moindre soucis vous pouvez contactez mon développeur via la commande \`?sugg\` qui se fera un plaisir de venir vous voir et vous aidez !"); + + //flag.send(msg); + + const embed = new MessageEmbed() + .setColor("RANDOM") + .setTitle("Bonjour, je m'appelle LanBot") + .setDescription("Je suis content que vous m'ayez choisi pour vous assister dans votre serveur et je me ferai une joie de mettre mes commandes et ma puissance de calcul à votre contribution.\n\nJe vous laisse le plaisir de faire la commande \`?init\` pour m'initialiser et suivre mes indications !\n\nSi vous avez le moindre soucis vous pouvez contactez mon développeur via la commande \`?sugg\` qui se fera un plaisir de venir vous voir et vous aidez !") + .setTimestamp() + .setFooter("Développé et Créé par lantium#9402"); + + flag.send(embed); +}; + diff --git a/events/guild/guildDelete.js b/events/guild/guildDelete.js new file mode 100644 index 0000000..24a2098 --- /dev/null +++ b/events/guild/guildDelete.js @@ -0,0 +1,3 @@ +module.exports = async (client, guild, member) => { + await client.deleteGuild(guild); +}; \ No newline at end of file diff --git a/events/message/directMessage.js b/events/message/directMessage.js new file mode 100644 index 0000000..b42d0fd --- /dev/null +++ b/events/message/directMessage.js @@ -0,0 +1,17 @@ +const { MessageEmbed } = require("discord.js"); + +module.exports = (client, message) => { + const user = message.author; + if (user.bot) return; + + const embed = new MessageEmbed() + .setAuthor(`${user.username} (${user.id})`) + .setColor("#ffa500") + .setDescription(`**Action**: ouverture ticket\n**Raison**: ${message.content}\nUtilisateur ${user}`) + .setThumbnail(user.avatarURL()) + .setTimestamp() + .setFooter(message.author.username, message.author.avatarURL()); + + user.send("Nous avons reçu votre ticket, on vous répondra d'est que possible !"); + client.channels.cache.get('815483099034943488').send(embed); +} \ No newline at end of file diff --git a/events/message/message.js b/events/message/message.js new file mode 100644 index 0000000..2cd335c --- /dev/null +++ b/events/message/message.js @@ -0,0 +1,92 @@ +const { Collection } = require('discord.js'); + +module.exports = async (client, message) => { + const settings = await client.getGuild(message.guild); + //const dbUser = await client.getUser(message.member); + + + if (message.channel.type === "dm") return client.emit("directMessage", message); + if (message.author.bot) return; + + + // reaction à tous les messages des membres via leur ID sur une guilde + //if (message.guild.id == "720405633228079185") { + //if (message.member.id == "475730695889879071") return message.channel.send(`${message.author.username} Au nom de <@721861508723638383> et de mon plaisir je te botte le cul https://tenor.com/view/funny-cut-throat-black-and-white-im-gonna-kill-you-kill-you-gif-7390009 !`); + //if (message.member.id == "327193195085824001") return message.channel.send(` Chef oui Chef ! <@327193195085824001>`); + //if (message.member.id == "721861508723638383") return message.channel.send(`${message.author.tag} Nous te vengerons https://tenor.com/view/running-hug-embrace-i-miss-you-good-to-see-you-again-gif-15965620 `); + + + // reaction à tous les messages des membres via leur ID + //if (message.member.id == "319931881741352980") return message.channel.send(` Nous t'avons lu haut GRANDE <@319931881741352980> :green_heart:`); + + /*if (!dbUser) await client.createUser({ + guildID: message.member.guild.id, + guildName: message.member.guild.name, + userID: message.member.id, + username: message.member.user.tag, + });*/ + + if (!message.content.startsWith(settings.prefix)) return; + + const lantium = message.member.id == "327193195085824001"; + + if (message.channel.send === true ); + + const args = message.content.slice(settings.prefix.length).split(/ +/); + const commandName = args.shift().toLowerCase(); + const user = message.mentions.users.first(); + +//si la commande n'existe pas, le bot ne réagit pas sauf si il y a les aliases + const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.help.aliases && cmd.help.aliases.includes(commandName)); + if (!command) return; + + +// vérification des permissions avant exécution des commandes qui contiennent permissions dans comma,d.help.permissions + if (command.help.permissions && !message.member.hasPermission('BAN_MEMBERS') && message.author.id !== "327193195085824001" && message.author.id !== "761547180724060181") return message.reply("Tu n'as pas les permissions pour taper cette commande ! https://tenor.com/view/tiananmen-square-prostest-tank-block-gif-4724995"); + +// pour utiliser le args dans le help des commandes + explication de comment utiliser la commande + if (command.help.args && !args.length) { + let noArgsReply = `il me faut des arguments pour cette commande, ${message.author}!`; + + if (command.help.usage) noArgsReply += `\nVoici comment utiliser la commande: \`${settings.prefix}${command.help.name} ${command.help.usage}\`` + + return message.channel.send(noArgsReply); + } + +if (command.help.isUserAdmin && !user) return message.reply("Il faut mentionner un utilisateur"); + + + // vérification des permissions avant exécution des commandes qui contiennent permissions dans comma,d.help.permissions + if (command.help.isUserAdmin && message.guild.member(user).hasPermission('BAN_MEMBERS')) return message.reply(`Tu ne peux pas utiliser la commande ${command.help.name} sur cet utilisateur !`); + + +// pour le cooldowns + utilisation de cooldown dans le help des commandes + if (!client.cooldowns.has(command.help.name)) { + client.cooldowns.set(command.help.name, new Collection()); + } + + const timeNow = Date.now(); + const tStamps = client.cooldowns.get(command.help.name); +//permet de définir par défault 5 secondes entre toutes les commandes, sauf si cooldown est modifié dans une commande + const cdAmount = (command.help.cooldown || 5) * 1000; + +//vérifie si l'utilisateur est dans la collection + if (tStamps.has(message.author.id)) { + const cdExpirationTime = tStamps.get(message.author.id) + cdAmount; + + if (timeNow < cdExpirationTime) { + timeLeft = (cdExpirationTime - timeNow) / 1000; + return message.reply(`Merci d'attendre ${timeLeft.toFixed(0)} seconde(s) avant de ré-utiliser la commande \`${command.help.name}\`.`); + } + } + +//permet de supprimer le membre de la collection si le cooldowns est fini + tStamps.set(message.author.id, timeNow); + setTimeout(() => tStamps.delete(message.author.id), cdAmount); + + + command.run(client, message, args, settings); +} + + +//, dbUser \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..3fc589f --- /dev/null +++ b/main.js @@ -0,0 +1,27 @@ +const { Client, Collection } = require('discord.js'); +const { loadCommands, loadEvents } = require("./util/loader"); + +const client = new Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] }); +require("./util/functions")(client); +client.config = require("./config"); +client.mongoose = require("./util/mongoose"); +client.queue = new Map(); + +//correspond à client.commands, client.cooldowns +["commands", "cooldowns", "category", "name"].forEach(x => client[x] = new Collection()); + + + +/* TODO ligne exécution commande DEBUG !!!! + +const message = ("say") +const settings = client.getGuild(message.guild); +module.exports.run(client, message, "hello", settings); */ + + +loadCommands(client); +loadEvents(client); +client.mongoose.init(); + +//lien vers le token du bot +client.login(client.config.TOKEN); \ No newline at end of file diff --git a/models/guild.js b/models/guild.js new file mode 100644 index 0000000..3b0c635 --- /dev/null +++ b/models/guild.js @@ -0,0 +1,15 @@ +const mongoose = require("mongoose"); +const { DEFAULTSETTINGS: defaults } = require("../config"); + +const guildSchema = mongoose.Schema({ + _id: mongoose.Schema.Types.ObjectId, + guildID: String, + guildName: String, + prefix: { + "type": String, + "default": defaults.prefix + }, + +}); + +module.exports = mongoose.model("Guild", guildSchema); diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..c513899 --- /dev/null +++ b/models/index.js @@ -0,0 +1,6 @@ +module.exports = { + Guild: require("./guild"), + User: require("./user"), + Role: require("./role"), + //Ticket: require("./ticket") +}; \ No newline at end of file diff --git a/models/role.js b/models/role.js new file mode 100644 index 0000000..32337d3 --- /dev/null +++ b/models/role.js @@ -0,0 +1,15 @@ +const mongoose = require("mongoose"); +const { DEFAULTSETTINGS: defaults } = require("../config"); + +const roleSchema = mongoose.Schema({ + _id: mongoose.Schema.Types.ObjectId, + guildID: String, + guildName: String, + roleID: { + "type": String, + "default": defaults.role + } + +}); + +module.exports = mongoose.model("Role", roleSchema); \ No newline at end of file diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..3ad0878 --- /dev/null +++ b/models/user.js @@ -0,0 +1,19 @@ +const mongoose = require("mongoose"); + +const userSchema = mongoose.Schema({ + _id: mongoose.Schema.Types.ObjectId, + guildID: String, + guildName: String, + userID: String, + username: String, + experience: { + "type": Number, + "default": 0 + }, + level: { + "type": Number, + "default": 0 + }, +}); + +module.exports = mongoose.model("User", userSchema); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9964d3f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1489 @@ +{ + "name": "lanbot", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@derhuerst/http-basic": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.1.tgz", + "integrity": "sha512-Rmn7qQQulw2sxJ8qGfZ7OuqMWuhz8V+L5xnYKMF5cXVcYqmgWqlVEAme90pF7Ya8OVhxVxLmhh0rI2k6t7ITWw==", + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "@discordjs/builders": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.5.0.tgz", + "integrity": "sha512-HP5y4Rqw68o61Qv4qM5tVmDbWi4mdTFftqIOGRo33SNPpLJ1Ga3KEIR2ibKofkmsoQhEpLmopD1AZDs3cKpHuw==", + "requires": { + "@sindresorhus/is": "^4.0.1", + "discord-api-types": "^0.22.0", + "ow": "^0.27.0", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.0" + } + }, + "@discordjs/collection": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" + }, + "@discordjs/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "@discordjs/node-pre-gyp": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/node-pre-gyp/-/node-pre-gyp-0.2.0.tgz", + "integrity": "sha512-2PIodKAuDLZZ8LGVFiQkZicco9PGcUICU/NlMqNMXuy91qMGKosOkDkzj4x+Kl1WYR1r2Y/fyOIgje5zezavYQ==", + "requires": { + "detect-libc": "^1.0.3", + "mkdirp": "^0.5.5", + "needle": "^2.6.0", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rc": "^1.2.8", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + }, + "dependencies": { + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@discordjs/opus": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/opus/-/opus-0.4.0.tgz", + "integrity": "sha512-89PRSuvBKBvZLkftVqRnQ9/rPXG9zDjKdbtlGC0RiZ6hJYFdWb4ND/maMgJPkTAvlIrRChm67eZOuIYhiKBDbQ==", + "requires": { + "@discordjs/node-pre-gyp": "^0.2.0", + "node-addon-api": "^3.1.0" + } + }, + "@sapphire/async-queue": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", + "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==" + }, + "@sindresorhus/is": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", + "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" + }, + "@types/bson": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", + "requires": { + "@types/node": "*" + } + }, + "@types/mongodb": { + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.8.tgz", + "integrity": "sha512-8qNbL5/GFrljXc/QijcuQcUMYZ1iWNcqnJ6tneROwbfU0LsAjQ9bmq3aHi5lWXM4cyBPd2F/n9INAk/pZZttHw==", + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==" + }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "requires": { + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "array-move": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-move/-/array-move-3.0.1.tgz", + "integrity": "sha512-H3Of6NIn2nNU1gsVDqDnYKY/LCdWvCMMOWifNGhKcVQgiZ6nOek39aESOvro6zmueP07exSl93YLvkN4fZOkSg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bent": { + "version": "7.3.12", + "resolved": "https://registry.npmjs.org/bent/-/bent-7.3.12.tgz", + "integrity": "sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==", + "requires": { + "bytesish": "^0.4.1", + "caseless": "~0.12.0", + "is-stream": "^2.0.0" + } + }, + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "bson": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "bytesish": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/bytesish/-/bytesish-0.4.4.tgz", + "integrity": "sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "cheerio": { + "version": "1.0.0-rc.5", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz", + "integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==", + "requires": { + "cheerio-select-tmp": "^0.1.0", + "dom-serializer": "~1.2.0", + "domhandler": "^4.0.0", + "entities": "~2.1.0", + "htmlparser2": "^6.0.0", + "parse5": "^6.0.0", + "parse5-htmlparser2-tree-adapter": "^6.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + }, + "domutils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz", + "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" + } + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "htmlparser2": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.1.tgz", + "integrity": "sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.4.4", + "entities": "^2.0.0" + } + } + } + }, + "cheerio-select-tmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz", + "integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==", + "requires": { + "css-select": "^3.1.2", + "css-what": "^4.0.0", + "domelementtype": "^2.1.0", + "domhandler": "^4.0.0", + "domutils": "^2.4.4" + }, + "dependencies": { + "dom-serializer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + }, + "domutils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz", + "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "css-select": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz", + "integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^4.0.0", + "domhandler": "^4.0.0", + "domutils": "^2.4.3", + "nth-check": "^2.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + }, + "domutils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.5.0.tgz", + "integrity": "sha512-Ho16rzNMOFk2fPwChGh3D2D9OEHAfG19HgmRR2l+WLSsIstNsAYBzePH412bL0y5T44ejABIVfTHQ8nqi/tBCg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + } + } + }, + "css-what": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz", + "integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==" + }, + "dateformat": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.5.1.tgz", + "integrity": "sha512-OD0TZ+B7yP7ZgpJf5K2DIbj3FZvFvxgFUuaqA/V5zTjAtAAXZ1E8bktHxmAGs4x5b7PflqA9LeQ84Og7wYtF7Q==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "discord-api-types": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", + "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" + }, + "discord-together": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/discord-together/-/discord-together-1.2.0.tgz", + "integrity": "sha512-L1G20599PxkaGv7QQ6KGF1GVCdcAZ0FE6ua0E1CPuoXbYLT+gLLuZKRC9ysw4+ygNKCy9RNn7fonydmJxq00Yw==", + "requires": { + "discord.js": "^13.1.0", + "node-fetch": "^2.6.1" + }, + "dependencies": { + "@discordjs/collection": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", + "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==" + }, + "discord.js": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.1.0.tgz", + "integrity": "sha512-gxO4CXKdHpqA+WKG+f5RNnd3srTDj5uFJHgOathksDE90YNq/Qijkd2WlMgTTMS6AJoEnHxI7G9eDQHCuZ+xDA==", + "requires": { + "@discordjs/builders": "^0.5.0", + "@discordjs/collection": "^0.2.1", + "@discordjs/form-data": "^3.0.1", + "@sapphire/async-queue": "^1.1.4", + "@types/ws": "^7.4.7", + "discord-api-types": "^0.22.0", + "node-fetch": "^2.6.1", + "ws": "^7.5.1" + } + } + } + }, + "discord.js": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.1.tgz", + "integrity": "sha512-VwZkVaUAIOB9mKdca0I5MefPMTQJTNg0qdgi1huF3iwsFwJ0L5s/Y69AQe+iPmjuV6j9rtKoG0Ta0n9vgEIL6w==", + "requires": { + "@discordjs/collection": "^0.1.6", + "@discordjs/form-data": "^3.0.1", + "abort-controller": "^3.0.0", + "node-fetch": "^2.6.1", + "prism-media": "^1.2.2", + "setimmediate": "^1.0.5", + "tweetnacl": "^1.0.3", + "ws": "^7.3.1" + } + }, + "discordjs-ytdl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/discordjs-ytdl/-/discordjs-ytdl-2.2.0.tgz", + "integrity": "sha512-++3lALtGxCJELHmv1hVJjhdeLyFaiC0uraZLJWYb/JRAtE2X5sc/mPsDXj9k09T+wBJ3KJZj7vy6qvfUE06jrA==", + "requires": { + "ffmpeg-static": "^4.2.7", + "opusscript": "0.0.7", + "simple-youtube-api": "^5.2.1", + "ytdl-core": "^4.4.5" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "ffmpeg": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/ffmpeg/-/ffmpeg-0.0.4.tgz", + "integrity": "sha1-HEYN+OfaUSf2LO70v6BsWciWMMs=", + "requires": { + "when": ">= 0.0.1" + } + }, + "ffmpeg-static": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-4.2.7.tgz", + "integrity": "sha512-SGnOr2d+k0/9toRIv9t5/hN/DMYbm5XMtG0wVwGM1tEyXJAD6dbcWOEvfHq4LOySm9uykKL6LMC4eVPeteUnbQ==", + "requires": { + "@derhuerst/http-basic": "^8.2.0", + "env-paths": "^2.2.0", + "https-proxy-agent": "^5.0.0", + "progress": "^2.0.3" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "generate-password": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.6.0.tgz", + "integrity": "sha512-YUJTQkApkLT/fru0QdYWP0lVZdPKhF5kXCP24sgI4gR/vFMJFopCj5t1+9FAKIYcML/nxzx2PMkA1ymO1FC+tQ==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "html-to-text": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-5.1.1.tgz", + "integrity": "sha512-Bci6bD/JIfZSvG4s0gW/9mMKwBRoe/1RWLxUME/d6WUSZCdY7T60bssf/jFf7EYXRyqU4P5xdClVqiYU0/ypdA==", + "requires": { + "he": "^1.2.0", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.11", + "minimist": "^1.2.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.55.tgz", + "integrity": "sha512-koZJ89uLZufDvToeWO5BrC4CR4OUfHnUz2qoPs/daQH6qq3IN62QFxCTZ+bKaCE0xaoCAJYE4AXre8AbghCrhg==" + } + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "iso8601-duration": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.3.0.tgz", + "integrity": "sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ==" + }, + "kareem": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", + "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "lyrics-finder": { + "version": "21.7.0", + "resolved": "https://registry.npmjs.org/lyrics-finder/-/lyrics-finder-21.7.0.tgz", + "integrity": "sha512-AMaJ+MdbdemYOWM1Kxd/vzn23OD66/fdemaJWN9dU0qsxK6d09rODSphygAvaGka6mgfHaFlHN+ETHv/d60ftw==", + "requires": { + "encoding": "^0.1.13", + "html-to-text": "^5.1.1", + "node-fetch": "^2.6.0" + } + }, + "m3u8stream": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.3.tgz", + "integrity": "sha512-0nAcdrF8YJKUkb6PzWdvGftTPyCVWgoiot1AkNVbPKTeIGsWs6DrOjifrJ0Zi8WQfQmD2SuVCjkYIOip12igng==", + "requires": { + "miniget": "^4.0.0", + "sax": "^1.2.4" + } + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "mime-db": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", + "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" + }, + "mime-types": { + "version": "2.1.29", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", + "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "requires": { + "mime-db": "1.46.0" + } + }, + "miniget": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.0.tgz", + "integrity": "sha512-IzTOaNgBw/qEpzkPTE7X2cUVXQfSKbG8w52Emi93zb+Zya2ZFrbmavpixzebuDJD9Ku4ecbaFlC7Y1cEESzQtQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "mongodb": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz", + "integrity": "sha512-Y+Ki9iXE9jI+n9bVtbTOOdK0B95d6wVGSucwtBkvQ+HIvVdTCfpVRp01FDC24uhC/Q2WXQ8Lpq3/zwtB5Op9Qw==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "mongoose": { + "version": "5.11.18", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.18.tgz", + "integrity": "sha512-RsrPR9nhkXZbO3ml0DcmdbfeMvFNhgFrP81S6o1P+lFnDTNEKYnGNRCIL+ojD69wj7H5jJaAdZ0SJ5IlKxCHqw==", + "requires": { + "@types/mongodb": "^3.5.27", + "bson": "^1.1.4", + "kareem": "2.3.2", + "mongodb": "3.6.4", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.8.3", + "mquery": "3.2.4", + "ms": "2.1.2", + "regexp-clone": "1.0.0", + "safe-buffer": "5.2.1", + "sift": "7.0.1", + "sliced": "1.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + }, + "mpath": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz", + "integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA==" + }, + "mquery": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.4.tgz", + "integrity": "sha512-uOLpp7iRX0BV1Uu6YpsqJ5b42LwYnmu0WeF/f8qgD/On3g0XDaQM6pfn0m6UxO6SM8DioZ9Bk6xxbWIGHm2zHg==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "node-addon-api": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", + "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-superfetch": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/node-superfetch/-/node-superfetch-0.2.3.tgz", + "integrity": "sha512-xOqifvw/3N+tIeeC80/TNJXkoxDZm8JWc7/0VBkJ86ttQTlJvoicuVaeJlKKHYRlmC2O6ygNIhNPwLYX4bxqdA==", + "requires": { + "form-data": "^4.0.0", + "node-fetch": "^2.6.1" + } + }, + "nodejs": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/nodejs/-/nodejs-0.0.0.tgz", + "integrity": "sha1-RyL6LhisTrc6Qq4W0B41hKErdTE=" + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "opusscript": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.7.tgz", + "integrity": "sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg==" + }, + "ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "requires": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + } + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "requires": { + "parse5": "^6.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "prism-media": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.7.tgz", + "integrity": "sha512-thS1z3L6BDmf724sqLC73bHGjSYArFTYHa7cqInyS3EdDNTHKgDCXy7l+IhRvlnX7aFNiUb8jJcC+R8ezxwgMA==" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "scrape-yt": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/scrape-yt/-/scrape-yt-1.4.8.tgz", + "integrity": "sha512-+fPLszuoY6/r5xYdMpP8afAmmz2FLnJqQs7uJILQFV9Q/NMa3YsUuv9DnfT0daxXFyPbLpAb5BQbOzhiU1m1lQ==", + "requires": { + "bent": "^7.3.0", + "cheerio": "^1.0.0-rc.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "sift": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", + "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-youtube-api": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/simple-youtube-api/-/simple-youtube-api-5.2.1.tgz", + "integrity": "sha512-vmndP9Bkh35tifn2OwY+th2imSsfYtmDqczgdOW5yEARFzvSoR8VSQFsivJnctfV5QHQUL6VrOpNdbmDRLh9Bg==", + "requires": { + "iso8601-duration": "^1.2.0", + "node-fetch": "^2.6.0" + } + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "string-progressbar": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string-progressbar/-/string-progressbar-1.0.3.tgz", + "integrity": "sha512-dbHlrfEqNv4giJR3gHkpj94tOlVRvkeqQZR2efac9UWwRQbkCyQEDWqcXuXALdd1psH+fY6Mdr/YaV/Il+jqhg==" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "ts-mixer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", + "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "ytdl-core": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.9.1.tgz", + "integrity": "sha512-6Jbp5RDhUEozlaJQAR+l8oV8AHsx3WUXxSyPxzE6wOIAaLql7Hjiy0ZM58wZoyj1YEenlEPjEqcJIjKYKxvHtQ==", + "requires": { + "m3u8stream": "^0.8.3", + "miniget": "^4.0.0", + "sax": "^1.1.3" + } + }, + "ytdl-core-discord": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ytdl-core-discord/-/ytdl-core-discord-1.2.5.tgz", + "integrity": "sha512-VS7Z7q9sfEpmTBWs31qU36O+qt52eLKCcbjs1VgkptwsHkeq2v6gBthUs6+4ZT6EzZopuZMSP/joZ0urXa1gcA==", + "requires": { + "@types/node": "^14.14.14", + "prism-media": "^1.2.3", + "ytdl-core": "^4.2.1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fafafda --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "dependencies": { + "@discordjs/opus": "^0.4.0", + "array-move": "^3.0.1", + "dateformat": "^4.5.1", + "discord-together": "^1.2.0", + "discord.js": "^12.5.1", + "discordjs-ytdl": "^2.2.0", + "dotenv": "^8.2.0", + "ffmpeg": "^0.0.4", + "ffmpeg-static": "^4.2.7", + "fs": "^0.0.1-security", + "generate-password": "^1.6.0", + "lyrics-finder": "^21.7.0", + "moment": "^2.29.1", + "mongodb": "^3.6.4", + "mongoose": "^5.11.18", + "ms": "^2.1.3", + "node-fetch": "^2.6.1", + "node-superfetch": "^0.2.3", + "nodejs": "0.0.0", + "scrape-yt": "^1.4.8", + "simple-youtube-api": "^5.1.1", + "string-progressbar": "^1.0.3", + "ytdl-core": "^4.9.1", + "ytdl-core-discord": "^1.2.5" + }, + "name": "lanbot", + "version": "1.0.0", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "description": "" +} diff --git a/sounds/putmusichere.mp3 b/sounds/putmusichere.mp3 new file mode 100644 index 0000000..e69de29 diff --git a/template commande.txt b/template commande.txt new file mode 100644 index 0000000..adf3984 --- /dev/null +++ b/template commande.txt @@ -0,0 +1,29 @@ +const { MESSAGES } = require("../../util/constants"); +const { canModifyQueue } = require("../../util/LanBot"); + +module.exports.run = (client, message, args, settings) => { + message.channel.send("Pong ! "); +}; + +module.exports.help = MESSAGES.COMMANDS.; + + + +const { MESSAGES } = require("../../util/constants"); + +module.exports.run = (client, message, args, settings) => { + const channel = message.member.voice.channel; + if (!channel) return message.channel.send('Vous devez être dans un salon vocal pour utiliser cette commande !''); + let queue = message.client.queue.get(message.guild.id) + if(!queue) return message.channel.send({ + embed: { + description: "Aucune musique de jouer, donc impossible d'utiliser la commande !", + color: 'BLACK' + } + }) + message.react('✅') + queue.songs = [] + queue.connection.dispatcher.end('Fin!') +}; + +module.exports.help = MESSAGES.COMMANDS.MUSIQUE.STOP; \ No newline at end of file diff --git a/util/LanBot.js b/util/LanBot.js new file mode 100644 index 0000000..19f9d18 --- /dev/null +++ b/util/LanBot.js @@ -0,0 +1,27 @@ +exports.canModifyQueue = (member) => { + const { channelID } = member.voice; + const botChannel = member.guild.voice.channelID; + + if (channelID !== botChannel) { + return; + } + + return true; + }; + + let config; + + try { + config = require("../config"); + } catch (error) { + config = null; + } + + exports.TOKEN = config.TOKEN; + exports.YOUTUBE_API_KEY = config.YOUTUBE_API_KEY; + //exports.SOUNDCLOUD_CLIENT_ID = config.SOUNDCLOUD_CLIENT_ID; + exports.MAX_PLAYLIST_SIZE = config.MAX_PLAYLIST_SIZE; + exports.PRUNING = config.PRUNING; + exports.STAY_TIME = config.STAY_TIME; + exports.DEFAULT_VOLUME = config.DEFAULT_VOLUME; + //exports.LOCALE = config.LOCALE; \ No newline at end of file diff --git a/util/constants.js b/util/constants.js new file mode 100644 index 0000000..9a605e5 --- /dev/null +++ b/util/constants.js @@ -0,0 +1,357 @@ +const MESSAGES = { + COMMANDS: { + ADMIN: { + CONFIG: { + name: "config", + aliases: ['config'], + category: 'admin', + description: "Modifier la base de données !\n disponible : **prefix** / **logChannel** / **welcomeMessage**\nAttention pour le **logChannel** merci de mettre l'ID du salon !", + cooldown: 3, + usage: [' '], + isUserAdmin: false, + permissions: true, + args: true, + }, + CHARGEMENT: { + name: "chargement", + aliases: ['chargement', 'init'], + category: 'admin', + description: "Config à faire pour le premier lancement du bot !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: true, + args: false, + }, + }, + DEVELOPPEUR: { + EVAL: { + name: "eval", + aliases: ['eval'], + category: 'developpeur', + description: "Renvoie un code javascript testé !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: true, + }, + RELOAD: { + name: "reload", + aliases: ['reload'], + category: 'developpeur', + description: "Reboot le bot !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + }, + INFORMATIONS: { + BOTINFO: { + name: "botinfo", + aliases: ['botinfo', 'bi'], + category: 'informations', + description: "Renvoie des informations concernant le bot !", + cooldown: 4, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + SERVERINFO: { + name: "serverinfo", + aliases: ['serverinfo', 'si'], + category: 'informations', + description: "Renvoie des informations concernant le serveur !", + cooldown: 4, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + STATS: { + name: "stats", + aliases: ['stats'], + category: 'informations', + description: "Renvoie des Statistiques !", + cooldown: 4, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + USERINFO: { + name: "userinfo", + aliases: ['userinfo', 'ui'], + category: 'informations', + description: "Permet d'avoir les informations de la personne mentionnée", + cooldown: 10, + usage: ['[<@user>]'], + isUserAdmin: false, + permissions: false, + args: false, + }, + }, + MUSIQUE: { + JOIN: { + name: "join", + aliases: ['join'], + category: 'musique', + description: "Connecte le bot au canal vocal !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + LEAVE: { + name: "leave", + aliases: ['leave'], + category: 'musique', + description: "Déconnecte le bot du canal vocal !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + LOOP: { + name: "loop", + aliases: ['loop'], + category: 'musique', + description: "Rejoue la musique lancé !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + LYRICS: { + name: "lyrics", + aliases: ['lyrics'], + category: 'musique', + description: "Envoie les paroles de la musique joué", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + MOVE: { + name: "Move", + aliases: ['move'], + category: 'musique', + description: "Déplacez les chansons de la file d'attente", + cooldown: 3, + usage: [' '], + isUserAdmin: false, + permissions: false, + args: true, + }, + SHUFFLE: { + name: "shuffle", + aliases: ['shuffle'], + category: 'musique', + description: "Lance la liste de lecture en aléatoire", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + SKIP: { + name: "skip", + aliases: ['skip'], + category: 'musique', + description: "Lance la prochaine musique de la liste d'attente", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + SKIPTO: { + name: "skipto", + aliases: ['skipto'], + category: 'musique', + description: "Passer au numéro de file d'attente sélectionné", + cooldown: 3, + usage: ['numéro de la musique'], + isUserAdmin: false, + permissions: false, + args: true, + }, + STOP: { + name: "stop", + aliases: ['stop'], + category: 'musique', + description: "Arrête la musique et fait quitter le bot du salon vocal", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + VOLUME: { + name: "VOLUME", + aliases: ['volume', 'vol'], + category: 'musique', + description: "Règle le volume du bot !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + }, + UTILITAIRE: { + HELP: { + name: "help", + aliases: ['help'], + category: 'utilitaire', + description: "Renvoie une liste de commandes ou les informations sur une seule !", + cooldown: 3, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + PING: { + name: "ping", + aliases: ['ping'], + category: 'utilitaire', + description: "Renvoie pong ! + la latence", + cooldown: 10, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + YT: { + name: "yt", + aliases: ['yt'], + category: 'utilitaire', + description: "Youtube Together", + cooldown: 10, + usage: [''], + isUserAdmin: false, + permissions: false, + args: false, + }, + }, + }, +}; + +exports.MESSAGES = MESSAGES; \ No newline at end of file diff --git a/util/functions.js b/util/functions.js new file mode 100644 index 0000000..888106c --- /dev/null +++ b/util/functions.js @@ -0,0 +1,33 @@ +const mongoose = require("mongoose"); +const { Guild, User, Ticket } = require("../models/index"); + +module.exports = client => { + client.createGuild = async guild => { + const merged = Object.assign({ _id: mongoose.Types.ObjectId() }, guild); + const createGuild = await new Guild(merged); + createGuild.save() + .then(g => console.log(`Nouveau serveur -> ${g.guildName}`)); + + }; + + client.getGuild = async guild => { + const data = await Guild.findOne({ guildID: guild.id }); + if (data) return data; + return client.config.DEFAULTSETTINGS; + }; + + client.updateGuild = async (guild, settings) => { + let data = await client.getGuild(guild); + if (typeof data !== "object") data = {}; + for (const key in settings) { + if (data[key] !== settings[key]) data[key] = settings[key]; + } + return data.updateOne(settings); + }; + + client.deleteGuild = async guild => { + const guilde = await client.getGuild(guild) + await guilde.delete() + }; + +}; diff --git a/util/loader.js b/util/loader.js new file mode 100644 index 0000000..af9bf99 --- /dev/null +++ b/util/loader.js @@ -0,0 +1,33 @@ +const fs = require("fs"); + +//Fonction pour récupérer les fichiers dans les sous-dossier +const loadCommands = (client, dir = "./commands/") => { + fs.readdirSync(dir).forEach(dirs => { + const commands = fs.readdirSync(`${dir}/${dirs}/`).filter(files => files.endsWith(".js")); + + for(const file of commands) { + const getFileName = require(`../${dir}/${dirs}/${file}`); + client.commands.set(getFileName.help.name, getFileName); + console.log(`Commande chargée: ${getFileName.help.name}`); + }; + }); + }; + + //Fonction pour les Events + const loadEvents = (client, dir = "./events/") => { + fs.readdirSync(dir).forEach(dirs => { + const events = fs.readdirSync(`${dir}/${dirs}/`).filter(files => files.endsWith(".js")); + + for(const event of events) { + const evt = require(`../${dir}/${dirs}/${event}`); + const evtName = event.split(".")[0]; + client.on(evtName, evt.bind(null, client)); + console.log(`Evenement chargé: ${evtName}`); + }; + }); + }; + + module.exports = { + loadCommands, + loadEvents, + } \ No newline at end of file diff --git a/util/mongoose.js b/util/mongoose.js new file mode 100644 index 0000000..2ba70ff --- /dev/null +++ b/util/mongoose.js @@ -0,0 +1,22 @@ +const mongoose = require("mongoose"); +const { DBCONNECTION } = require("../config"); + +module.exports = { + init: () => { + const mongOptions = { + useNewUrlParser: true, + useUnifiedTopology: true, + useCreateIndex: true, + useFindAndModify: false, + autoIndex: false, // Don't build indexes + poolSize: 10, // Maintain up to 10 socket connections + serverSelectionTimeoutMS: 5000, // Keep trying to send operations for 5 seconds + socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity + family: 4 // Use IPv4, skip trying IPv6 + } + + mongoose.connect(DBCONNECTION, mongOptions); + mongoose.Promise = global.Promise; + mongoose.connection.on("connected", () => console.log("Mongoose est connecté !")); + } +} \ No newline at end of file