mirror of
https://github.com/JonnyBro/JaBa.git
synced 2025-04-02 12:10:47 +05:00
update dev...
This commit is contained in:
commit
9fe5e01cdb
352 changed files with 1333 additions and 13982 deletions
|
@ -16,7 +16,6 @@ class Seek extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,11 +14,7 @@ class BaseCommand {
|
|||
/**
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.guildOnly = options.guildOnly || true;
|
||||
/**
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.ownerOnly = options.ownerOnly || false;
|
||||
this.ownerOnly = (options.ownerOnly === true ? true : false) || false;
|
||||
this.dirname = options.dirname || false;
|
||||
/**
|
||||
* @type {String}
|
||||
|
|
135
base/JaBa.js
135
base/JaBa.js
|
@ -1,5 +1,5 @@
|
|||
const { Client, Collection, SlashCommandBuilder, ContextMenuCommandBuilder } = require("discord.js"),
|
||||
{ Player } = require("../helpers/Music/dist/index"),
|
||||
{ Player } = require("discord-player-play-dl"),
|
||||
{ DiscordTogether } = require("../helpers/discordTogether"),
|
||||
{ GiveawaysManager } = require("discord-giveaways"),
|
||||
{ REST } = require("@discordjs/rest"),
|
||||
|
@ -46,16 +46,14 @@ class JaBa extends Client {
|
|||
|
||||
this.discordTogether = new DiscordTogether(this);
|
||||
|
||||
playdl.getFreeClientID().then(clientID => {
|
||||
playdl.setToken({
|
||||
soundcloud: {
|
||||
client_id: clientID
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.player = new Player(this);
|
||||
|
||||
playdl.getFreeClientID().then(id => playdl.setToken({
|
||||
soundcloud: {
|
||||
client_id: id
|
||||
}
|
||||
}));
|
||||
|
||||
this.player.on("trackStart", async (queue, track) => {
|
||||
const m = await queue.metadata.channel.send({ content: this.translate("music/play:NOW_PLAYING", { songName: track.title }, queue.metadata.channel.guild.data.language) });
|
||||
if (track.durationMS > 1) {
|
||||
|
@ -90,6 +88,9 @@ class JaBa extends Client {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bot account, connect to DB and update docs
|
||||
*/
|
||||
async init() {
|
||||
this.login(this.config.token);
|
||||
|
||||
|
@ -107,8 +108,8 @@ class JaBa extends Client {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} dir
|
||||
* Load commands from directory
|
||||
* @param {String} dir Directory where's all commands located
|
||||
* @returns
|
||||
*/
|
||||
async loadCommands(dir) {
|
||||
|
@ -148,15 +149,15 @@ class JaBa extends Client {
|
|||
}
|
||||
|
||||
try {
|
||||
if (!this.config.production) {
|
||||
if (this.config.production) {
|
||||
await rest.put(
|
||||
Routes.applicationGuildCommands(this.config.user, this.config.support.id), {
|
||||
Routes.applicationCommands(this.config.user), {
|
||||
body: commands
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await rest.put(
|
||||
Routes.applicationCommands(this.config.user), {
|
||||
Routes.applicationGuildCommands(this.config.user, this.config.support.id), {
|
||||
body: commands
|
||||
}
|
||||
);
|
||||
|
@ -169,9 +170,9 @@ class JaBa extends Client {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} dir
|
||||
* @param {String} file
|
||||
* Load single command in directory
|
||||
* @param {String} dir Directory where command is
|
||||
* @param {String} file Filename of the command
|
||||
*/
|
||||
async loadCommand(dir, file) {
|
||||
const Command = require(path.join(dir, `${file}.js`));
|
||||
|
@ -196,9 +197,9 @@ class JaBa extends Client {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} dir
|
||||
* @param {String} name
|
||||
* Unload command from cache
|
||||
* @param {String} dir Directory of the command
|
||||
* @param {String} name Name of the command
|
||||
*/
|
||||
async unloadCommand(dir, name) {
|
||||
delete require.cache[require.resolve(`${dir}${path.sep}${name}.js`)];
|
||||
|
@ -207,8 +208,8 @@ class JaBa extends Client {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} dir
|
||||
* Load events from directory
|
||||
* @param {String} dir Directory where's all events located
|
||||
* @returns
|
||||
*/
|
||||
async loadEvents(dir) {
|
||||
|
@ -231,15 +232,18 @@ class JaBa extends Client {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default language
|
||||
*/
|
||||
get defaultLanguage() {
|
||||
return this.languages.find(language => language.default).name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {Array} args
|
||||
* @param {String} locale
|
||||
* Translate from key to language
|
||||
* @param {String} key Key
|
||||
* @param {Array} args Arguments for translation
|
||||
* @param {String} locale Language
|
||||
*/
|
||||
translate(key, args, locale = this.defaultLanguage) {
|
||||
const language = this.translations.get(locale);
|
||||
|
@ -248,22 +252,45 @@ class JaBa extends Client {
|
|||
return language(key, args);
|
||||
}
|
||||
|
||||
printDate(date, format = false, locale = this.defaultLanguage) {
|
||||
const languageData = this.languages.find((language) => language.name === locale || language.aliases.includes(locale));
|
||||
if (!format) format = languageData.defaultMomentFormat;
|
||||
/**
|
||||
* Returns beautified date
|
||||
* @param {Date} date Date
|
||||
* @param {String | null} format Format for moment
|
||||
* @param {String} locale Language
|
||||
* @returns {String} Beautified date
|
||||
*/
|
||||
printDate(date, format = "", locale = this.defaultLanguage) {
|
||||
const languageData = this.languages.find(language => language.name === locale || language.aliases.includes(locale));
|
||||
if (format === "" || format === null) format = languageData.defaultMomentFormat;
|
||||
|
||||
return moment(new Date(date))
|
||||
.locale(languageData.moment)
|
||||
.format(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert given time
|
||||
* @param {String} time Time
|
||||
* @param {Boolean} type Type (To now = true or from now = false)
|
||||
* @param {Boolean} noPrefix Use prefix?
|
||||
* @param {String} locale Language
|
||||
* @returns {String} Time
|
||||
*/
|
||||
convertTime(time, type = false, noPrefix = false, locale = this.defaultLanguage) {
|
||||
const languageData = this.languages.find((language) => language.name === locale || language.aliases.includes(locale));
|
||||
const languageData = this.languages.find(language => language.name === locale || language.aliases.includes(locale));
|
||||
const m = moment(time).locale(languageData.moment);
|
||||
|
||||
return (type ? m.toNow(noPrefix) : m.fromNow(noPrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get noun for number
|
||||
* @param {Number} number Number
|
||||
* @param {String} one String for one
|
||||
* @param {String} two String for two
|
||||
* @param {String} five String for five
|
||||
* @returns
|
||||
*/
|
||||
getNoun(number, one, two, five) {
|
||||
let n = Math.abs(number);
|
||||
n %= 100;
|
||||
|
@ -275,6 +302,12 @@ class JaBa extends Client {
|
|||
return five;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find or create user in DB
|
||||
* @param {Array} param0 { id: User ID }
|
||||
* @param {Boolean} isLean Return JSON instead Mongoose model?
|
||||
* @returns {import("./User")} Mongoose model or JSON of this user
|
||||
*/
|
||||
async findOrCreateUser({ id: userID }, isLean) {
|
||||
if (this.databaseCache.users.get(userID)) return isLean ? this.databaseCache.users.get(userID).toJSON() : this.databaseCache.users.get(userID);
|
||||
else {
|
||||
|
@ -299,58 +332,70 @@ class JaBa extends Client {
|
|||
}
|
||||
}
|
||||
|
||||
async findOrCreateMember({ id: memberID, guildID }, isLean) {
|
||||
if (this.databaseCache.members.get(`${memberID}${guildID}`)) return isLean ? this.databaseCache.members.get(`${memberID}${guildID}`).toJSON() : this.databaseCache.members.get(`${memberID}${guildID}`);
|
||||
/**
|
||||
* Find or create member in DB
|
||||
* @param {Array} param0 { id: Member ID }
|
||||
* @param {Boolean} isLean Return JSON instead Mongoose model?
|
||||
* @returns {import("./Member")} Mongoose model or JSON of this member
|
||||
*/
|
||||
async findOrCreateMember({ id: memberID, guildId }, isLean) {
|
||||
if (this.databaseCache.members.get(`${memberID}${guildId}`)) return isLean ? this.databaseCache.members.get(`${memberID}${guildId}`).toJSON() : this.databaseCache.members.get(`${memberID}${guildId}`);
|
||||
else {
|
||||
let memberData = (isLean ? await this.membersData.findOne({
|
||||
guildID,
|
||||
guildID: guildId,
|
||||
id: memberID
|
||||
}).lean() : await this.membersData.findOne({
|
||||
guildID,
|
||||
guildID: guildId,
|
||||
id: memberID
|
||||
}));
|
||||
if (memberData) {
|
||||
if (!isLean) this.databaseCache.members.set(`${memberID}${guildID}`, memberData);
|
||||
if (!isLean) this.databaseCache.members.set(`${memberID}${guildId}`, memberData);
|
||||
|
||||
return memberData;
|
||||
} else {
|
||||
memberData = new this.membersData({
|
||||
id: memberID,
|
||||
guildID: guildID
|
||||
guildID: guildId
|
||||
});
|
||||
await memberData.save();
|
||||
const guild = await this.findOrCreateGuild({
|
||||
id: guildID
|
||||
id: guildId
|
||||
});
|
||||
if (guild) {
|
||||
guild.members.push(memberData._id);
|
||||
await guild.save();
|
||||
}
|
||||
this.databaseCache.members.set(`${memberID}${guildID}`, memberData);
|
||||
this.databaseCache.members.set(`${memberID}${guildId}`, memberData);
|
||||
|
||||
return isLean ? memberData.toJSON() : memberData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async findOrCreateGuild({ id: guildID }, isLean) {
|
||||
if (this.databaseCache.guilds.get(guildID)) return isLean ? this.databaseCache.guilds.get(guildID).toJSON() : this.databaseCache.guilds.get(guildID);
|
||||
/**
|
||||
* Find or create guild in DB
|
||||
* @param {Array} param0 { id: Guild ID }
|
||||
* @param {Boolean} isLean Return JSON instead Mongoose model?
|
||||
* @returns {import("./Guild")} Mongoose model or JSON of this guild
|
||||
*/
|
||||
async findOrCreateGuild({ id: guildId }, isLean) {
|
||||
if (this.databaseCache.guilds.get(guildId)) return isLean ? this.databaseCache.guilds.get(guildId).toJSON() : this.databaseCache.guilds.get(guildId);
|
||||
else {
|
||||
let guildData = (isLean ? await this.guildsData.findOne({
|
||||
id: guildID
|
||||
id: guildId
|
||||
}).populate("members").lean() : await this.guildsData.findOne({
|
||||
id: guildID
|
||||
id: guildId
|
||||
}).populate("members"));
|
||||
if (guildData) {
|
||||
if (!isLean) this.databaseCache.guilds.set(guildID, guildData);
|
||||
if (!isLean) this.databaseCache.guilds.set(guildId, guildData);
|
||||
|
||||
return guildData;
|
||||
} else {
|
||||
guildData = new this.guildsData({
|
||||
id: guildID
|
||||
id: guildId
|
||||
});
|
||||
await guildData.save();
|
||||
this.databaseCache.guilds.set(guildID, guildData);
|
||||
this.databaseCache.guilds.set(guildId, guildData);
|
||||
|
||||
return isLean ? guildData.toJSON() : guildData;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Automod extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("automod")
|
||||
.setDescription(client.translate("administration/automod:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Automod extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Autorole extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("autorole")
|
||||
.setDescription(client.translate("administration/autorole:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -19,7 +20,7 @@ class Autorole extends BaseCommand {
|
|||
.setDescription(client.translate("common:ROLE"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,10 +11,11 @@ class Config extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("config")
|
||||
.setDescription(client.translate("administration/config:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Goodbye extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("goodbye")
|
||||
.setDescription(client.translate("administration/goodbye:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addSubcommand(subcommand => subcommand.setName("test")
|
||||
.setDescription(client.translate("administration/goodbye:TEST"))
|
||||
|
@ -29,7 +30,7 @@ class Goodbye extends BaseCommand {
|
|||
),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Set extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("set")
|
||||
.setDescription(client.translate("administration/set:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addStringOption(option => option.setName("type")
|
||||
.setDescription(client.translate("owner/debug:TYPE"))
|
||||
|
@ -29,7 +30,6 @@ class Set extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -50,8 +50,10 @@ class Set extends BaseCommand {
|
|||
const type = interaction.options.getString("type");
|
||||
const member = interaction.options.getMember("user");
|
||||
if (member.user.bot) return interaction.error("misc:BOT_USER", null, { ephemeral: true });
|
||||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id
|
||||
id: member.id,
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
const int = interaction.options.getInteger("int");
|
||||
if (int < 0) return interaction.error("administration/set:INVALID_NUMBER", null, { ephemeral: true });
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setbirthdays extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setbirthdays")
|
||||
.setDescription(client.translate("administration/setbirthdays:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Setbirthdays extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setlang extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setlang")
|
||||
.setDescription(client.translate("administration/setlang:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addStringOption(option => option.setName("language")
|
||||
.setDescription(client.translate("common:LANGUAGE"))
|
||||
|
@ -21,7 +22,7 @@ class Setlang extends BaseCommand {
|
|||
)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setmodlogs extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setmodlogs")
|
||||
.setDescription(client.translate("administration/setmodlogs:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Setmodlogs extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setnews extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setnews")
|
||||
.setDescription(client.translate("administration/setnews:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Setnews extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setreports extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setreports")
|
||||
.setDescription(client.translate("administration/setreports:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Setreports extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Setsuggests extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setsuggests")
|
||||
.setDescription(client.translate("administration/setsuggests:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addBooleanOption(option => option.setName("state")
|
||||
.setDescription(client.translate("common:STATE"))
|
||||
|
@ -20,7 +21,7 @@ class Setsuggests extends BaseCommand {
|
|||
.addChannelTypes(ChannelType.GuildText)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,13 +11,14 @@ class Stealemoji extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("stealemoji")
|
||||
.setDescription(client.translate("administration/stealemoji:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addStringOption(option => option.setName("emoji")
|
||||
.setDescription(client.translate("common:EMOJI"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,7 @@ class Welcome extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("welcome")
|
||||
.setDescription(client.translate("administration/welcome:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addSubcommand(subcommand => subcommand.setName("test")
|
||||
.setDescription(client.translate("administration/goodbye:TEST"))
|
||||
|
@ -29,7 +30,7 @@ class Welcome extends BaseCommand {
|
|||
),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,11 +11,11 @@ class Achievements extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("achievements")
|
||||
.setDescription(client.translate("economy/achievements:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Bank extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("bank")
|
||||
.setDescription(client.translate("economy/bank:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("option")
|
||||
.setDescription(client.translate("economy/bank:OPTION"))
|
||||
.setRequired(true)
|
||||
|
@ -23,7 +24,6 @@ class Bank extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -48,19 +48,18 @@ class Bank extends BaseCommand {
|
|||
if (isNaN(credits) || credits < 1) return interaction.error("misc:OPTION_NAN_ALL");
|
||||
if (data.memberData.money < credits) return interaction.error("economy/bank:NOT_ENOUGH_CREDIT", { money: `**${credits}** ${client.getNoun(credits, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}` });
|
||||
|
||||
data.memberData.money -= credits;
|
||||
data.memberData.bankSold += credits;
|
||||
await data.memberData.save();
|
||||
|
||||
const info = {
|
||||
user: interaction.translate("economy/transactions:BANK"),
|
||||
amount: credits,
|
||||
date: Date.now(),
|
||||
type: "send"
|
||||
};
|
||||
|
||||
data.memberData.transactions.push(info);
|
||||
|
||||
data.memberData.money -= credits;
|
||||
data.memberData.bankSold += credits;
|
||||
await data.memberData.save();
|
||||
|
||||
interaction.success("economy/bank:SUCCESS_DEP", {
|
||||
money: `**${credits}** ${client.getNoun(credits, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}`
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ class Birthdate extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("birthdate")
|
||||
.setDescription(client.translate("economy/birthdate:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addIntegerOption(option => option.setName("day")
|
||||
.setDescription(client.translate("economy/birthdate:DAY"))
|
||||
.setRequired(true))
|
||||
|
@ -36,7 +37,6 @@ class Birthdate extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Divorce extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("divorce")
|
||||
.setDescription(client.translate("economy/divorce:DESCRIPTION")),
|
||||
.setDescription(client.translate("economy/divorce:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ class ImportMee6 extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("importmee6")
|
||||
.setDescription(client.translate("economy/importmee6:DESCRIPTION")),
|
||||
.setDescription(client.translate("economy/importmee6:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
const asyncForEach = async (collection, callback) => {
|
||||
const allPromises = collection.map(async key => {
|
||||
await callback(key);
|
||||
});
|
||||
|
||||
return await Promise.all(allPromises);
|
||||
};
|
||||
|
||||
class Leaderboard extends BaseCommand {
|
||||
/**
|
||||
*
|
||||
|
@ -11,6 +19,7 @@ class Leaderboard extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("leaderboard")
|
||||
.setDescription(client.translate("economy/leaderboard:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("type")
|
||||
.setDescription(client.translate("owner/debug:TYPE"))
|
||||
.setRequired(true)
|
||||
|
@ -21,7 +30,6 @@ class Leaderboard extends BaseCommand {
|
|||
)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -40,6 +48,7 @@ class Leaderboard extends BaseCommand {
|
|||
*/
|
||||
async execute(client, interaction) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const type = interaction.options.getString("type");
|
||||
const isOnMobile = JSON.stringify(Object.keys(interaction.member.presence.clientStatus)) === JSON.stringify(["mobile"]);
|
||||
if (isOnMobile) interaction.followUp({
|
||||
|
@ -48,24 +57,24 @@ class Leaderboard extends BaseCommand {
|
|||
});
|
||||
|
||||
if (type === "money") {
|
||||
const members = await client.membersData.find({
|
||||
guildID: interaction.guildId
|
||||
}).lean(),
|
||||
membersLeaderboard = members.map(m => {
|
||||
return {
|
||||
id: m.id,
|
||||
money: m.money + m.bankSold
|
||||
};
|
||||
}).sort((a, b) => b.money - a.money);
|
||||
const membersLeaderboard = [],
|
||||
membersData = await client.membersData.find({ guildID: interaction.guildId }).lean();
|
||||
|
||||
await asyncForEach(membersData, async member => {
|
||||
membersLeaderboard.push({
|
||||
id: member.id,
|
||||
money: member.money + member.bankSold
|
||||
});
|
||||
});
|
||||
membersLeaderboard.sort((a, b) => b.money - a.money);
|
||||
if (membersLeaderboard.length > 20) membersLeaderboard.length = 20;
|
||||
|
||||
let userNames = "";
|
||||
let money = "";
|
||||
for (let i = 0; i < membersLeaderboard.length; i++) {
|
||||
const data = membersLeaderboard[i];
|
||||
const user = await client.users.fetch(data.id);
|
||||
|
||||
userNames += `**${i + 1}**. ${user}\n`;
|
||||
userNames += `**${i + 1}**. <@${data.id}>\n`;
|
||||
money += `${data.money}\n`;
|
||||
}
|
||||
|
||||
|
@ -78,7 +87,7 @@ class Leaderboard extends BaseCommand {
|
|||
})
|
||||
.setColor(client.config.embed.color)
|
||||
.addFields({
|
||||
name: interaction.translate("economy/leaderboard:TOP"),
|
||||
name: interaction.translate("common:USER"),
|
||||
value: userNames,
|
||||
inline: true
|
||||
}, {
|
||||
|
@ -91,14 +100,14 @@ class Leaderboard extends BaseCommand {
|
|||
embeds: [embed]
|
||||
});
|
||||
} else if (type === "level") {
|
||||
const membersLeaderboard = [];
|
||||
client.membersData.find({
|
||||
guildID: interaction.guildId
|
||||
}).lean().then(async m => {
|
||||
await membersLeaderboard.push({
|
||||
id: m.id,
|
||||
level: m.level,
|
||||
xp: m.exp
|
||||
const membersLeaderboard = [],
|
||||
membersData = await client.membersData.find({ guildID: interaction.guildId }).lean();
|
||||
|
||||
await asyncForEach(membersData, async member => {
|
||||
membersLeaderboard.push({
|
||||
id: member.id,
|
||||
level: member.level,
|
||||
xp: member.exp
|
||||
});
|
||||
});
|
||||
membersLeaderboard.sort((a, b) => b.level - a.level);
|
||||
|
@ -109,9 +118,8 @@ class Leaderboard extends BaseCommand {
|
|||
const xp = [];
|
||||
for (let i = 0; i < membersLeaderboard.length; i++) {
|
||||
const data = membersLeaderboard[i];
|
||||
const user = await client.users.fetch(data.id);
|
||||
|
||||
userNames.push(`**${i + 1}**. ${user.tag}`);
|
||||
userNames.push(`**${i + 1}**. <@${data.id}>`);
|
||||
level.push(`${data.level}`);
|
||||
xp.push(`${data.xp} / ${5 * (data.level * data.level) + 80 * data.level + 100}`);
|
||||
}
|
||||
|
@ -126,7 +134,7 @@ class Leaderboard extends BaseCommand {
|
|||
.setColor(client.config.embed.color)
|
||||
.addFields([
|
||||
{
|
||||
name: interaction.translate("economy/leaderboard:TOP"),
|
||||
name: interaction.translate("common:USER"),
|
||||
value: userNames.join("\n"),
|
||||
inline: true
|
||||
},
|
||||
|
@ -146,24 +154,24 @@ class Leaderboard extends BaseCommand {
|
|||
embeds: [embed]
|
||||
});
|
||||
} else if (type === "rep") {
|
||||
const users = await client.usersData.find({
|
||||
rep: { $gt: 0 }
|
||||
}).lean(),
|
||||
usersLeaderboard = users.map(u => {
|
||||
return {
|
||||
id: u.id,
|
||||
rep: u.rep
|
||||
};
|
||||
}).sort((a, b) => b.rep - a.rep);
|
||||
const usersLeaderboard = [],
|
||||
usersData = await client.usersData.find({ rep: { $gt: 0 } }).lean();
|
||||
|
||||
await asyncForEach(usersData, async user => {
|
||||
usersLeaderboard.push({
|
||||
id: user.id,
|
||||
rep: user.rep
|
||||
});
|
||||
});
|
||||
usersLeaderboard.sort((a, b) => b.rep - a.rep);
|
||||
if (usersLeaderboard.length > 20) usersLeaderboard.length = 20;
|
||||
|
||||
let userNames = "";
|
||||
let rep = "";
|
||||
for (let i = 0; i < usersLeaderboard.length; i++) {
|
||||
const data = usersLeaderboard[i];
|
||||
const user = await client.users.fetch(data.id);
|
||||
|
||||
userNames += `**${i + 1}**. ${user}\n`;
|
||||
userNames += `**${i + 1}**. <@${data.id}>\n`;
|
||||
rep += `${data.rep}\n`;
|
||||
}
|
||||
|
||||
|
@ -176,7 +184,7 @@ class Leaderboard extends BaseCommand {
|
|||
})
|
||||
.setColor(client.config.embed.color)
|
||||
.addFields({
|
||||
name: interaction.translate("economy/leaderboard:TOP"),
|
||||
name: interaction.translate("common:USER"),
|
||||
value: userNames,
|
||||
inline: true
|
||||
}, {
|
|
@ -12,12 +12,12 @@ class Marry extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("marry")
|
||||
.setDescription(client.translate("economy/marry:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
const asyncForEach = async (collection, callback) => {
|
||||
const allPromises = collection.map(async key => {
|
||||
await callback(key);
|
||||
|
@ -18,11 +19,11 @@ class Money extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("money")
|
||||
.setDescription(client.translate("economy/money:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -44,9 +45,9 @@ class Money extends BaseCommand {
|
|||
const member = interaction.options.getMember("user") || interaction.member;
|
||||
if (member.user.bot) return interaction.error("economy/money:BOT_USER");
|
||||
|
||||
const memberData = (member.id === interaction.user.id) ? data.memberData : await client.findOrCreateMember({
|
||||
const memberData = member.id === interaction.user.id ? data.memberData : await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
const guilds = client.guilds.cache.filter(g => g.members.cache.find(m => m.id === member.id));
|
||||
|
@ -54,7 +55,7 @@ class Money extends BaseCommand {
|
|||
await asyncForEach(guilds, async guild => {
|
||||
const data = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: guild.id
|
||||
guildId: guild.id
|
||||
});
|
||||
globalMoney += data.money + data.bankSold;
|
||||
});
|
||||
|
|
|
@ -11,10 +11,10 @@ class Number extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("number")
|
||||
.setDescription(client.translate("economy/number:DESCRIPTION")),
|
||||
.setDescription(client.translate("economy/number:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -79,19 +79,19 @@ class Number extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: msg.author.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
memberData.money += won;
|
||||
|
||||
const info = {
|
||||
user: interaction.translate("economy/transactions:NUMBERS"),
|
||||
amount: won,
|
||||
date: Date.now(),
|
||||
type: "got"
|
||||
};
|
||||
|
||||
data.memberData.transactions.push(info);
|
||||
|
||||
memberData.money += won;
|
||||
await memberData.save();
|
||||
}
|
||||
collector.stop();
|
||||
|
|
|
@ -11,6 +11,7 @@ class Pay extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("pay")
|
||||
.setDescription(client.translate("economy/pay:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true))
|
||||
|
@ -19,7 +20,6 @@ class Pay extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -50,23 +50,31 @@ class Pay extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
const info = {
|
||||
user: member.user.tag,
|
||||
amount: amount,
|
||||
date: Date.now(),
|
||||
type: "send"
|
||||
};
|
||||
|
||||
data.memberData.transactions.push(info);
|
||||
data.memberData.money -= amount;
|
||||
await data.memberData.save();
|
||||
|
||||
memberData.money += amount;
|
||||
memberData.save();
|
||||
|
||||
const info1 = {
|
||||
user: member.user.tag,
|
||||
amount: amount,
|
||||
date: Date.now(),
|
||||
type: "send"
|
||||
};
|
||||
data.memberData.transactions.push(info1);
|
||||
|
||||
const info2 = {
|
||||
user: member.user.tag,
|
||||
amount: amount,
|
||||
date: Date.now(),
|
||||
type: "got"
|
||||
};
|
||||
data.memberData.transactions.push(info2);
|
||||
|
||||
interaction.success("economy/pay:SUCCESS", {
|
||||
user: member.toString(),
|
||||
amount: `**${amount}** ${client.getNoun(amount, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}`
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
const asyncForEach = async (collection, callback) => {
|
||||
const allPromises = collection.map(async key => {
|
||||
await callback(key);
|
||||
|
@ -18,11 +19,11 @@ class Profile extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("profile")
|
||||
.setDescription(client.translate("economy/profile:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ class Profile extends BaseCommand {
|
|||
|
||||
const memberData = (member.id === interaction.user.id ? data.memberData : await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
}));
|
||||
const userData = (member.id === interaction.user.id ? data.userData : await client.findOrCreateUser({
|
||||
id: member.id
|
||||
|
@ -59,7 +60,7 @@ class Profile extends BaseCommand {
|
|||
await asyncForEach(guilds, async guild => {
|
||||
const data = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: guild.id
|
||||
guildId: guild.id
|
||||
});
|
||||
globalMoney += data.money + data.bankSold;
|
||||
});
|
||||
|
|
|
@ -11,12 +11,12 @@ class Rep extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("rep")
|
||||
.setDescription(client.translate("economy/rep:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Rob extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("rob")
|
||||
.setDescription(client.translate("economy/rob:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true))
|
||||
|
@ -19,7 +20,6 @@ class Rob extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -45,9 +45,10 @@ class Rob extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
if (amount > memberData.money) return interaction.error("economy/rob:NOT_ENOUGH_MEMBER", { user: member.toString() });
|
||||
|
||||
const isInCooldown = memberData.cooldowns.rob || 0;
|
||||
if (isInCooldown) {
|
||||
if (isInCooldown > Date.now()) return interaction.error("economy/rob:COOLDOWN", { user: member.toString() });
|
||||
|
|
|
@ -11,12 +11,12 @@ class Setbio extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("setbio")
|
||||
.setDescription(client.translate("economy/setbio:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("text")
|
||||
.setDescription(client.translate("economy/profile:BIO"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Slots extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("slots")
|
||||
.setDescription(client.translate("economy/slots:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addIntegerOption(option => option.setName("amount")
|
||||
.setDescription(client.translate("common:INT"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -35,8 +35,9 @@ class Slots extends BaseCommand {
|
|||
*/
|
||||
async execute(client, interaction, data) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const amount = interaction.options.getInteger("amount");
|
||||
if (amount > data.memberData.money) return interaction.error("economy/slots:NOT_ENOUGH", { money: `**${amount}** ${client.getNoun(amount, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}` });
|
||||
if (amount > data.memberData.money) return interaction.error("economy/slots:NOT_ENOUGH", { money: `**${amount}** ${client.getNoun(amount, interaction.translate("misc:NOUNS:CREDIT:1"), interaction.translate("misc:NOUNS:CREDIT:2"), interaction.translate("misc:NOUNS:CREDIT:5"))}` }, { edit: true });
|
||||
|
||||
const fruits = ["🍎", "🍐", "🍌", "🍇", "🍉", "🍒", "🍓"];
|
||||
|
||||
|
@ -100,6 +101,8 @@ class Slots extends BaseCommand {
|
|||
|
||||
const toAdd = credits - amount;
|
||||
|
||||
data.memberData.money += toAdd;
|
||||
|
||||
const info = {
|
||||
user: interaction.translate("economy/slots:DESCRIPTION"),
|
||||
amount: toAdd,
|
||||
|
@ -107,7 +110,6 @@ class Slots extends BaseCommand {
|
|||
type: "got"
|
||||
};
|
||||
data.memberData.transactions.push(info);
|
||||
data.memberData.money += toAdd;
|
||||
|
||||
if (!data.userData.achievements.slots.achieved) {
|
||||
data.userData.achievements.slots.progress.now += 1;
|
||||
|
|
|
@ -12,12 +12,12 @@ class TicTacToe extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("tictactoe")
|
||||
.setDescription(client.translate("economy/tictactoe:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -42,9 +42,12 @@ class TicTacToe extends BaseCommand {
|
|||
}).then(async winner => {
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: winner.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
memberData.money += 100;
|
||||
await memberData.save();
|
||||
|
||||
const info = {
|
||||
user: interaction.translate("economy/transactions:TTT"),
|
||||
amount: 100,
|
||||
|
@ -52,9 +55,6 @@ class TicTacToe extends BaseCommand {
|
|||
type: "got"
|
||||
};
|
||||
memberData.transactions.push(info);
|
||||
|
||||
memberData.money += 100;
|
||||
await memberData.save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ class Transactions extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("transactions")
|
||||
.setDescription(client.translate("economy/transactions:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addBooleanOption(option => option.setName("clear")
|
||||
.setDescription(client.translate("economy/transactions:CLEAR"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Work extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("work")
|
||||
.setDescription(client.translate("economy/work:DESCRIPTION")),
|
||||
.setDescription(client.translate("economy/work:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -98,16 +98,16 @@ class Work extends BaseCommand {
|
|||
]);
|
||||
}
|
||||
|
||||
data.memberData.money += won;
|
||||
await data.memberData.save();
|
||||
|
||||
const info = {
|
||||
user: interaction.translate("economy/work:SALARY"),
|
||||
amount: won,
|
||||
date: Date.now(),
|
||||
type: "got"
|
||||
};
|
||||
|
||||
data.memberData.transactions.push(info);
|
||||
data.memberData.money += won;
|
||||
await data.memberData.save();
|
||||
|
||||
const messageOptions = {
|
||||
embeds: [embed]
|
||||
|
|
|
@ -11,13 +11,12 @@ class Eightball extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("8ball")
|
||||
.setDescription(client.translate("fun/8ball:DESCRIPTION"))
|
||||
.addStringOption(option =>
|
||||
option.setName("question")
|
||||
.setDescription(client.translate("fun/8ball:QUESTION"))
|
||||
.setRequired(true)),
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("question")
|
||||
.setDescription(client.translate("fun/8ball:QUESTION"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -36,17 +35,18 @@ class Eightball extends BaseCommand {
|
|||
*/
|
||||
async execute(client, interaction) {
|
||||
await interaction.deferReply();
|
||||
const question = interaction.options.getString("question");
|
||||
|
||||
if (!question.endsWith("?")) return interaction.replyT("fun/8ball:ERR_QUESTION", null, { ephemeral: true });
|
||||
const question = interaction.options.getString("question");
|
||||
if (!question.endsWith("?")) return interaction.error("fun/8ball:ERR_QUESTION", null, { ephemeral: true });
|
||||
|
||||
const answerN = client.functions.randomNum(1, 20);
|
||||
const answer = interaction.translate(`fun/8ball:RESPONSE_${answerN}`);
|
||||
await client.wait(2000);
|
||||
await client.wait(5000);
|
||||
|
||||
interaction.editReply({
|
||||
content: answer
|
||||
});
|
||||
interaction.replyT("fun/8ball:ANSWER", {
|
||||
question,
|
||||
answer
|
||||
}, { edit: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ class Crab extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("crab")
|
||||
.setDescription(client.translate("fun/crab:DESCRIPTION")),
|
||||
.setDescription(client.translate("fun/crab:DESCRIPTION"))
|
||||
.setDMPermission(true),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const { SlashCommandBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
const BaseCommand = require("../../base/BaseCommand"),
|
||||
fetch = require("node-fetch");
|
||||
|
||||
class LMGTFY extends BaseCommand {
|
||||
/**
|
||||
|
@ -11,13 +12,15 @@ class LMGTFY extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("lmgtfy")
|
||||
.setDescription(client.translate("fun/lmgtfy:DESCRIPTION"))
|
||||
.addStringOption(option =>
|
||||
option.setName("question")
|
||||
.setDescription(client.translate("fun/8ball:QUESTION"))
|
||||
.setRequired(true)),
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("query")
|
||||
.setDescription(client.translate("fun/lmgtfy:QUERY"))
|
||||
.setRequired(true))
|
||||
.addBooleanOption(option => option.setName("short")
|
||||
.setDescription(client.translate("fun/lmgtfy:SHORT"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -35,12 +38,23 @@ class LMGTFY extends BaseCommand {
|
|||
* @param {Object} data
|
||||
*/
|
||||
async execute(client, interaction) {
|
||||
const question = interaction.options.getString("question").replace(/[' '_]/g, "+");
|
||||
const query = interaction.options.getString("query").replace(/[' '_]/g, "+"),
|
||||
short = interaction.options.getBoolean("short"),
|
||||
url = `https://letmegooglethat.com/?q=${query}`;
|
||||
|
||||
interaction.reply({
|
||||
content: `<https://letmegooglethat.com/?q=${question}>`,
|
||||
ephemeral: true
|
||||
});
|
||||
if (short) {
|
||||
const res = await fetch(`https://is.gd/create.php?format=simple&url=${encodeURIComponent(url)}`).then(res => res.text());
|
||||
|
||||
interaction.reply({
|
||||
content: `<${res}>`,
|
||||
ephemeral: true
|
||||
});
|
||||
} else {
|
||||
interaction.reply({
|
||||
content: `<${url}>`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ class Lovecalc extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("lovecalc")
|
||||
.setDescription(client.translate("fun/lovecalc:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option =>
|
||||
option.setName("first_member")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
|
@ -21,7 +22,6 @@ class Lovecalc extends BaseCommand {
|
|||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ class Memes extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("memes")
|
||||
.setDescription(client.translate("fun/memes:DESCRIPTION")),
|
||||
.setDescription(client.translate("fun/memes:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -49,13 +49,14 @@ class Memes extends BaseCommand {
|
|||
.addOptions(tags)
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
const msg = await interaction.editReply({
|
||||
content: interaction.translate("common:AVAILABLE_OPTIONS"),
|
||||
fetchReply: true,
|
||||
components: [row]
|
||||
});
|
||||
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (2 * 60 * 1000) });
|
||||
const collector = msg.createMessageComponentCollector({ filter, idle: (2 * 60 * 1000) });
|
||||
|
||||
collector.on("collect", async i => {
|
||||
if (i.isSelectMenu() && i.customId === "memes_select") {
|
||||
|
|
|
@ -11,10 +11,10 @@ class Activity extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("activity")
|
||||
.setDescription(client.translate("general/activity:DESCRIPTION")),
|
||||
.setDescription(client.translate("general/activity:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Afk extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("afk")
|
||||
.setDescription(client.translate("general/afk:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("message")
|
||||
.setDescription(client.translate("common:MESSAGE"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ class Avatar extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("avatar")
|
||||
.setDescription(client.translate("general/avatar:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Emoji extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("emoji")
|
||||
.setDescription(client.translate("general/emoji:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("emoji")
|
||||
.setDescription(client.translate("common:EMOJI"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Help extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("help")
|
||||
.setDescription(client.translate("general/help:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option =>
|
||||
option.setName("command")
|
||||
.setDescription(client.translate("owner/reload:COMMAND"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class Help extends BaseCommand {
|
|||
|
||||
commands.forEach(c => {
|
||||
if (!categories.includes(c.category)) {
|
||||
if (c.category === "Owner" && interaction.member.id !== client.config.owner.id) return;
|
||||
if (c.category === "Owner" && interaction.user.id !== client.config.owner.id) return;
|
||||
categories.push(c.category);
|
||||
}
|
||||
});
|
||||
|
@ -70,13 +70,14 @@ class Help extends BaseCommand {
|
|||
.addOptions(categoriesRows)
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
const msg = await interaction.editReply({
|
||||
content: interaction.translate("common:AVAILABLE_OPTIONS"),
|
||||
fetchReply: true,
|
||||
components: [row]
|
||||
});
|
||||
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (15 * 1000) });
|
||||
const collector = msg.createMessageComponentCollector({ filter, idle: (15 * 1000) });
|
||||
|
||||
collector.on("collect", async i => {
|
||||
if (i.isSelectMenu() && (i.customId === "help_category_select" || i.customId === "help_commands_select")) {
|
||||
|
@ -133,7 +134,10 @@ function getPermName(bitfield = 0) {
|
|||
|
||||
function generateCommandHelp(interaction, command) {
|
||||
const cmd = interaction.client.commands.get(command);
|
||||
if (!cmd) return interaction.error("general/help:NOT_FOUND", { search: command }, { edit: true });
|
||||
if (!cmd) return interaction.error("general/help:NOT_FOUND", { command }, { edit: true });
|
||||
const usage = interaction.translate(`${cmd.category.toLowerCase()}/${cmd.command.name}:USAGE`) === "" ?
|
||||
interaction.translate("misc:NO_ARGS")
|
||||
: interaction.translate(`${cmd.category.toLowerCase()}/${cmd.command.name}:USAGE`);
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({
|
||||
|
@ -148,7 +152,7 @@ function generateCommandHelp(interaction, command) {
|
|||
},
|
||||
{
|
||||
name: interaction.translate("general/help:FIELD_USAGE"),
|
||||
value: interaction.translate(`${cmd.category.toLowerCase()}/${cmd.command.name}:USAGE`)
|
||||
value: `*${cmd.guildOnly ? interaction.translate("general/help:GUILD_ONLY") : interaction.translate("general/help:NOT_GUILD_ONLY")}*\n\n` + usage
|
||||
},
|
||||
{
|
||||
name: interaction.translate("general/help:FIELD_EXAMPLES"),
|
||||
|
|
|
@ -12,12 +12,12 @@ class Minecraft extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("minecraft")
|
||||
.setDescription(client.translate("general/minecraft:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("ip")
|
||||
.setDescription(client.translate("common:IP"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Ping extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("ping")
|
||||
.setDescription(client.translate("general/ping:DESCRIPTION")),
|
||||
.setDescription(client.translate("general/ping:DESCRIPTION"))
|
||||
.setDMPermission(true),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const { SlashCommandBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand"),
|
||||
ms = require("ms");
|
||||
ms = require("ms"),
|
||||
moment = require("moment");
|
||||
|
||||
class Remindme extends BaseCommand {
|
||||
/**
|
||||
|
@ -12,6 +13,7 @@ class Remindme extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("remindme")
|
||||
.setDescription(client.translate("general/remindme:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("time")
|
||||
.setDescription(client.translate("owner/remindme:TIME"))
|
||||
.setRequired(true))
|
||||
|
@ -20,7 +22,6 @@ class Remindme extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -38,6 +39,8 @@ class Remindme extends BaseCommand {
|
|||
* @param {Object} data
|
||||
*/
|
||||
async execute(client, interaction, data) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const time = interaction.options.getString("time");
|
||||
const message = interaction.options.getString("message");
|
||||
const dateNow = Date.now();
|
||||
|
@ -54,7 +57,10 @@ class Remindme extends BaseCommand {
|
|||
data.userData.save();
|
||||
client.databaseCache.usersReminds.set(interaction.member.id, data.userData);
|
||||
|
||||
interaction.success("general/remindme:SAVED");
|
||||
interaction.success("general/remindme:SAVED", {
|
||||
message,
|
||||
time: moment(rData.createdAt).locale(interaction.guild.data.language).format("dddd, Do MMMM YYYY, HH:mm:ss")
|
||||
}, { edit: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ class Report extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("report")
|
||||
.setDescription(client.translate("general/report:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true))
|
||||
|
@ -19,7 +20,6 @@ class Report extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Serverinfo extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("serverinfo")
|
||||
.setDescription(client.translate("general/serverinfo:DESCRIPTION")),
|
||||
.setDescription(client.translate("general/serverinfo:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ class Shorturl extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("shorturl")
|
||||
.setDescription(client.translate("general/shorturl:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("url")
|
||||
.setDescription(client.translate("general/shorturl:URL"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class Shorturl extends BaseCommand {
|
|||
*/
|
||||
async execute(client, interaction) {
|
||||
const url = interaction.options.getString("url");
|
||||
const res = await fetch(`https://is.gd/create.php?format=simple&url=${encodeURI(url)}`).then(res => res.text());
|
||||
const res = await fetch(`https://is.gd/create.php?format=simple&url=${encodeURIComponent(url)}`).then(res => res.text());
|
||||
|
||||
interaction.reply({
|
||||
content: `<${res}>`,
|
||||
|
|
|
@ -10,10 +10,10 @@ class Staff extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("staff")
|
||||
.setDescription(client.translate("general/staff:DESCRIPTION")),
|
||||
.setDescription(client.translate("general/staff:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ class Stats extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("stats")
|
||||
.setDescription(client.translate("general/stats:DESCRIPTION")),
|
||||
.setDescription(client.translate("general/stats:DESCRIPTION"))
|
||||
.setDMPermission(true),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Suggest extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("suggest")
|
||||
.setDescription(client.translate("general/suggest:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("message")
|
||||
.setDescription(client.translate("common:MESSAGE"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ class Userinfo extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("userinfo")
|
||||
.setDescription(client.translate("general/userinfo:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ class Whois extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("whois")
|
||||
.setDescription(client.translate("general/whois:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("ip")
|
||||
.setDescription(client.translate("common:IP"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Clear extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("clear")
|
||||
.setDescription(client.translate("moderation/clear:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addStringOption(option => option.setName("option")
|
||||
.setDescription(client.translate("moderation/clear:OPTION"))
|
||||
|
@ -19,7 +20,7 @@ class Clear extends BaseCommand {
|
|||
.setDescription(client.translate("common:USER"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,13 +11,14 @@ class Clearwarns extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("clearwarns")
|
||||
.setDescription(client.translate("moderation/clearwarns:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
@ -38,7 +39,7 @@ class Clearwarns extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
memberData.sanctions = [];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { SlashCommandBuilder, ActionRowBuilder, SelectMenuBuilder, InteractionCollector, ComponentType, PermissionFlagsBits } = require("discord.js");
|
||||
const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand"),
|
||||
ms = require("ms");
|
||||
|
||||
|
@ -12,20 +12,44 @@ class Giveaway extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("giveaway")
|
||||
.setDescription(client.translate("moderation/giveaway:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addStringOption(option => option.setName("giveaway_id")
|
||||
.setDescription(client.translate("moderation/giveaway:GIVEAWAY_ID")))
|
||||
.addStringOption(option => option.setName("duration")
|
||||
.setDescription(client.translate("common:DURATION")))
|
||||
.addStringOption(option => option.setName("winners_count")
|
||||
.setDescription(client.translate("moderation/giveaway:WINNERS_COUNT")))
|
||||
.addStringOption(option => option.setName("prize")
|
||||
.setDescription(client.translate("moderation/giveaway:PRIZE")))
|
||||
.addBooleanOption(option => option.setName("isdrop")
|
||||
.setDescription(client.translate("moderation/giveaway:ISDROP"))),
|
||||
.addSubcommand(subcommand => subcommand.setName("create")
|
||||
.setDescription(client.translate("moderation/giveaway:CREATE"))
|
||||
.addStringOption(option => option.setName("duration")
|
||||
.setDescription(client.translate("common:DURATION"))
|
||||
.setRequired(true))
|
||||
.addIntegerOption(option => option.setName("winners_count")
|
||||
.setDescription(client.translate("moderation/giveaway:WINNERS_COUNT"))
|
||||
.setRequired(true))
|
||||
.addStringOption(option => option.setName("prize")
|
||||
.setDescription(client.translate("moderation/giveaway:PRIZE"))
|
||||
.setRequired(true))
|
||||
.addBooleanOption(option => option.setName("isdrop")
|
||||
.setDescription(client.translate("moderation/giveaway:ISDROP"))
|
||||
.setRequired(true))
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand.setName("reroll")
|
||||
.setDescription(client.translate("moderation/giveaway:REROLL"))
|
||||
.addStringOption(option => option.setName("giveaway_id")
|
||||
.setDescription(client.translate("moderation/giveaway:GIVEAWAY_ID"))
|
||||
.setRequired(true))
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand.setName("end")
|
||||
.setDescription(client.translate("moderation/giveaway:END"))
|
||||
.addStringOption(option => option.setName("giveaway_id")
|
||||
.setDescription(client.translate("moderation/giveaway:GIVEAWAY_ID"))
|
||||
.setRequired(true))
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand.setName("delete")
|
||||
.setDescription(client.translate("moderation/giveaway:DELETE"))
|
||||
.addStringOption(option => option.setName("giveaway_id")
|
||||
.setDescription(client.translate("moderation/giveaway:GIVEAWAY_ID"))
|
||||
.setRequired(true))
|
||||
),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
@ -42,154 +66,81 @@ class Giveaway extends BaseCommand {
|
|||
* @param {Object} data
|
||||
*/
|
||||
async execute(client, interaction) {
|
||||
const options = ["create", "reroll", "delete", "end"].map(tag =>
|
||||
JSON.parse(JSON.stringify({
|
||||
label: tag,
|
||||
value: tag
|
||||
}))
|
||||
);
|
||||
const command = interaction.options.getSubcommand();
|
||||
|
||||
const row = new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new SelectMenuBuilder()
|
||||
.setCustomId("giveaway_select")
|
||||
.setPlaceholder(client.translate("common:NOTHING_SELECTED"))
|
||||
.addOptions(options)
|
||||
);
|
||||
if (command === "create") {
|
||||
const currentGiveaways = client.giveawaysManager.giveaways.filter(g => g.guildId === interaction.guildId && !g.ended).length;
|
||||
if (currentGiveaways > 5) return interaction.error("moderation/giveaway:MAX_COUNT");
|
||||
|
||||
const msg = await interaction.reply({
|
||||
content: interaction.translate("common:AVAILABLE_OPTIONS"),
|
||||
components: [row],
|
||||
ephemeral: true,
|
||||
fetchReply: true
|
||||
});
|
||||
const duration = interaction.options.getString("duration");
|
||||
if (ms(duration) > ms("10d")) return interaction.error("moderation/giveaway:MAX_DURATION");
|
||||
|
||||
const filter = i => i.customId === "giveaway_select" && i.user.id === interaction.user.id;
|
||||
const collector = new InteractionCollector(client, {
|
||||
filter,
|
||||
componentType: ComponentType.SelectMenu,
|
||||
message: msg,
|
||||
idle: (30 * 1000)
|
||||
});
|
||||
const winnersCount = interaction.options.getInteger("winners_count");
|
||||
if (winnersCount > 10 || winnersCount < 1) return interaction.error("misc:INVALID_NUMBER_RANGE", { min: 1, max: 10 });
|
||||
|
||||
collector.on("collect", async i => {
|
||||
const option = i?.values[0];
|
||||
const prize = interaction.options.getString("prize");
|
||||
const isdrop = interaction.options.getBoolean("isdrop");
|
||||
|
||||
if (option === "create") {
|
||||
const currentGiveaways = client.giveawaysManager.giveaways.filter(g => g.guildId === interaction.guild.id && !g.ended).length;
|
||||
if (currentGiveaways > 5) return i.update({ content: interaction.translate("moderation/giveaway:MAX_COUNT") });
|
||||
|
||||
const duration = interaction.options.getString("duration");
|
||||
if (!duration) return i.update({ content: interaction.translate("moderation/giveaway:INVALID_CREATE") });
|
||||
if (ms(duration) > ms("10d")) return i.update({ content: interaction.translate("moderation/giveaway:MAX_DURATION") });
|
||||
|
||||
const winnersCount = interaction.options.getString("winners_count");
|
||||
if (!winnersCount) return i.update({ content: interaction.translate("moderation/giveaway:INVALID_CREATE") });
|
||||
if (isNaN(winnersCount) || winnersCount > 10 || winnersCount < 1) return i.update({ content: interaction.translate("misc:INVALID_NUMBER_RANGE", { min: 1, max: 10 }) });
|
||||
|
||||
const prize = interaction.options.getString("prize");
|
||||
if (!prize) return i.update({ content: interaction.translate("moderation/giveaway:INVALID_CREATE") });
|
||||
const isdrop = interaction.options.getString("isdrop");
|
||||
|
||||
client.giveawaysManager.start(interaction.channel, {
|
||||
duration: ms(duration),
|
||||
winnerCount: winnersCount,
|
||||
prize: prize,
|
||||
hostedBy: interaction.user,
|
||||
isDrop: isdrop,
|
||||
messages: {
|
||||
giveaway: interaction.translate("moderation/giveaway:TITLE"),
|
||||
giveawayEnded: interaction.translate("moderation/giveaway:ENDED"),
|
||||
timeRemaining: interaction.translate("moderation/giveaway:TIME_REMAINING"),
|
||||
inviteToParticipate: interaction.translate("moderation/giveaway:INVITE_PARTICIPATE"),
|
||||
winMessage: interaction.translate("moderation/giveaway:WIN_MESSAGE"),
|
||||
drawing: interaction.translate("moderation/giveaway:DRAWING"),
|
||||
dropMessage: interaction.translate("moderation/giveaway:DROP"),
|
||||
embedFooter: interaction.translate("moderation/giveaway:FOOTER"),
|
||||
noWinner: interaction.translate("moderation/giveaway:NO_WINNER"),
|
||||
winners: interaction.translate("moderation/giveaway:WINNERS"),
|
||||
endedAt: interaction.translate("moderation/giveaway:END_AT"),
|
||||
hostedBy: interaction.translate("moderation/giveaway:HOSTEDBY"),
|
||||
// units: {
|
||||
// seconds: interaction.translate("time:SECONDS", {
|
||||
// amount: ""
|
||||
// }).trim(),
|
||||
// minutes: interaction.translate("time:MINUTES", {
|
||||
// amount: ""
|
||||
// }).trim(),
|
||||
// hours: interaction.translate("time:HOURS", {
|
||||
// amount: ""
|
||||
// }).trim(),
|
||||
// days: interaction.translate("time:DAYS", {
|
||||
// amount: ""
|
||||
// }).trim()
|
||||
// }
|
||||
}
|
||||
}).then(() => {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:GIVEAWAY_CREATED"),
|
||||
components: []
|
||||
});
|
||||
});
|
||||
} else if (option === "reroll") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
if (!giveaway_id) return i.update({ content: interaction.translate("moderation/giveaway:MISSING_ID"), components: [] });
|
||||
|
||||
client.giveawaysManager.reroll(giveaway_id, {
|
||||
messages: {
|
||||
congrat: interaction.translate("moderation/giveaway:REROLL_CONGRAT"),
|
||||
error: interaction.translate("moderation/giveaway:REROLL_ERROR")
|
||||
}
|
||||
}).then(() => {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:GIVEAWAY_REROLLED"),
|
||||
components: []
|
||||
});
|
||||
}).catch(() => {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:NOT_FOUND_ENDED", {
|
||||
messageId: giveaway_id
|
||||
}),
|
||||
components: []
|
||||
});
|
||||
});
|
||||
} else if (option === "delete") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
if (!giveaway_id) return i.update({ content: interaction.translate("moderation/giveaway:MISSING_ID"), components: [] });
|
||||
|
||||
client.giveawaysManager.delete(giveaway_id).then(() => {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:GIVEAWAY_DELETED"),
|
||||
components: []
|
||||
});
|
||||
}).catch(() => {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:NOT_FOUND", {
|
||||
messageId: giveaway_id
|
||||
}),
|
||||
components: []
|
||||
});
|
||||
});
|
||||
} else if (option === "end") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
if (!giveaway_id) return i.update({ content: interaction.translate("moderation/giveaway:MISSING_ID"), components: [] });
|
||||
|
||||
try {
|
||||
client.giveawaysManager.end(giveaway_id);
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:GIVEAWAY_ENDED"),
|
||||
components: []
|
||||
});
|
||||
} catch (e) {
|
||||
return i.update({
|
||||
content: interaction.translate("moderation/giveaway:NOT_FOUND", {
|
||||
messageId: giveaway_id
|
||||
}),
|
||||
components: []
|
||||
});
|
||||
client.giveawaysManager.start(interaction.channel, {
|
||||
duration: ms(duration),
|
||||
winnerCount: winnersCount,
|
||||
prize: prize,
|
||||
hostedBy: interaction.user,
|
||||
isDrop: isdrop,
|
||||
messages: {
|
||||
giveaway: interaction.translate("moderation/giveaway:TITLE"),
|
||||
giveawayEnded: interaction.translate("moderation/giveaway:ENDED"),
|
||||
timeRemaining: interaction.translate("moderation/giveaway:TIME_REMAINING"),
|
||||
inviteToParticipate: interaction.translate("moderation/giveaway:INVITE_PARTICIPATE"),
|
||||
winMessage: interaction.translate("moderation/giveaway:WIN_MESSAGE"),
|
||||
drawing: interaction.translate("moderation/giveaway:DRAWING"),
|
||||
dropMessage: interaction.translate("moderation/giveaway:DROP"),
|
||||
embedFooter: interaction.translate("moderation/giveaway:FOOTER"),
|
||||
noWinner: interaction.translate("moderation/giveaway:NO_WINNER"),
|
||||
winners: interaction.translate("moderation/giveaway:WINNERS"),
|
||||
endedAt: interaction.translate("moderation/giveaway:END_AT"),
|
||||
hostedBy: interaction.translate("moderation/giveaway:HOSTED_BY")
|
||||
}
|
||||
}).then(() => {
|
||||
return interaction.success("moderation/giveaway:GIVEAWAY_CREATED", null, { ephemeral: true });
|
||||
});
|
||||
} else if (command === "reroll") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
|
||||
client.giveawaysManager.reroll(giveaway_id, {
|
||||
messages: {
|
||||
congrat: interaction.translate("moderation/giveaway:REROLL_CONGRAT"),
|
||||
error: interaction.translate("moderation/giveaway:REROLL_ERROR")
|
||||
}
|
||||
}).then(() => {
|
||||
return interaction.success("moderation/giveaway:GIVEAWAY_REROLLED");
|
||||
}).catch(() => {
|
||||
return interaction.error("moderation/giveaway:NOT_FOUND_ENDED", {
|
||||
messageId: giveaway_id
|
||||
}, { ephemeral: true });
|
||||
});
|
||||
} else if (command === "end") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
|
||||
try {
|
||||
client.giveawaysManager.end(giveaway_id);
|
||||
return interaction.success("moderation/giveaway:GIVEAWAY_ENDED");
|
||||
} catch (e) {
|
||||
return interaction.error("moderation/giveaway:NOT_FOUND", {
|
||||
messageId: giveaway_id
|
||||
}, { ephemeral: true });
|
||||
}
|
||||
});
|
||||
} else if (command === "delete") {
|
||||
const giveaway_id = interaction.options.getString("giveaway_id");
|
||||
|
||||
client.giveawaysManager.delete(giveaway_id).then(() => {
|
||||
return interaction.success("moderation/giveaway:GIVEAWAY_DELETED");
|
||||
}).catch(() => {
|
||||
return interaction.error("moderation/giveaway:NOT_FOUND", {
|
||||
messageId: giveaway_id
|
||||
}, { ephemeral: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,14 @@ class Poll extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("poll")
|
||||
.setDescription(client.translate("moderation/poll:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addStringOption(option => option.setName("question")
|
||||
.setDescription(client.translate("moderation/poll:QUESTION"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,13 +11,14 @@ class Unban extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("unban")
|
||||
.setDescription(client.translate("moderation/unban:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addStringOption(option => option.setName("user_id")
|
||||
.setDescription(client.translate("moderation/unban:ID"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -11,10 +11,11 @@ class Warn extends BaseCommand {
|
|||
command: new ContextMenuCommandBuilder()
|
||||
.setName("warn")
|
||||
.setType(ApplicationCommandType.User)
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
@ -40,12 +41,14 @@ class Warn extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId("warn_modal")
|
||||
.setTitle(interaction.translate("moderation/warn:MODAL_TITLE"));
|
||||
.setTitle(interaction.translate("moderation/warn:MODAL_TITLE", {
|
||||
nickname: member.user.tag
|
||||
}));
|
||||
|
||||
const reasonInput = new TextInputBuilder()
|
||||
.setCustomId("warn_reason")
|
||||
|
|
|
@ -11,13 +11,14 @@ class Warns extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("warns")
|
||||
.setDescription(client.translate("moderation/warns:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages)
|
||||
.addUserOption(option => option.setName("user")
|
||||
.setDescription(client.translate("common:USER"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
@ -39,7 +40,7 @@ class Warns extends BaseCommand {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
|
|
|
@ -10,10 +10,10 @@ class Back extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("back")
|
||||
.setDescription(client.translate("music/back:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/back:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { SlashCommandBuilder, ActionRowBuilder, SelectMenuBuilder, } = require("discord.js"),
|
||||
const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, EmbedBuilder, ButtonStyle } = require("discord.js"),
|
||||
{ joinVoiceChannel, createAudioResource, createAudioPlayer, getVoiceConnection, AudioPlayerStatus } = require("@discordjs/voice");
|
||||
const BaseCommand = require("../../base/BaseCommand"),
|
||||
fs = require("fs");
|
||||
|
@ -12,10 +12,13 @@ class Clips extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("clips")
|
||||
.setDescription(client.translate("music/clips:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/clips:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("query")
|
||||
.setDescription(client.translate("music/clips:QUERY"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -36,82 +39,191 @@ class Clips extends BaseCommand {
|
|||
fs.readdir("./clips", async function (err, files) {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (err) return console.log("Unable to read directory: " + err);
|
||||
const query = interaction.options.getString("query");
|
||||
|
||||
const clips = files.map(file => {
|
||||
const fileName = file.substring(0, file.length - 4);
|
||||
return {
|
||||
label: fileName,
|
||||
value: fileName
|
||||
};
|
||||
});
|
||||
if (err) {
|
||||
interaction.editReply({
|
||||
content: "```js\n" + err + "```"
|
||||
});
|
||||
return console.log("Unable to read directory: " + err);
|
||||
}
|
||||
|
||||
const row = new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new SelectMenuBuilder()
|
||||
.setCustomId("clips_select")
|
||||
.setPlaceholder(client.translate("common:NOTHING_SELECTED"))
|
||||
.addOptions(clips)
|
||||
);
|
||||
if (query === "list") {
|
||||
const clips = files.map(file => file.substring(0, file.length - 4));
|
||||
let currentPage = 0;
|
||||
const embeds = generateClipsEmbeds(interaction, clips);
|
||||
|
||||
await interaction.editReply({
|
||||
content: interaction.translate("music/clips:AVAILABLE_CLIPS"),
|
||||
components: [row]
|
||||
});
|
||||
const row = new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("clips_prev_page")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setEmoji("⬅️"),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("clips_next_page")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setEmoji("➡️"),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("clips_jump_page")
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
.setEmoji("↗️"),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("clips_stop")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setEmoji("⏹️"),
|
||||
);
|
||||
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (15 * 1000) });
|
||||
await interaction.editReply({
|
||||
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
|
||||
embeds: [embeds[currentPage]],
|
||||
components: [row]
|
||||
});
|
||||
|
||||
collector.on("collect", async i => {
|
||||
if (i.isSelectMenu() && i.customId === "clips_select") {
|
||||
const clip = i?.values[0];
|
||||
const voice = i.member.voice.channel;
|
||||
if (!voice) return i.update({ content: interaction.translate("music/play:NO_VOICE_CHANNEL"), components: [] });
|
||||
const queue = client.player.getQueue(i.guild.id);
|
||||
if (queue) return i.update({ content: interaction.translate("music/clips:ACTIVE_QUEUE"), components: [] });
|
||||
if (getVoiceConnection(i.guild.id)) return i.update({ content: interaction.translate("music/clips:ACTIVE_CLIP"), components: [] });
|
||||
if (!fs.existsSync(`./clips/${clip}.mp3`)) return i.update({ content: interaction.translate("music/clips:NO_FILE", { file: clip }), components: [] });
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (20 * 1000) });
|
||||
|
||||
try {
|
||||
const connection = joinVoiceChannel({
|
||||
channelId: voice.id,
|
||||
guildId: interaction.guild.id,
|
||||
adapterCreator: interaction.guild.voiceAdapterCreator
|
||||
});
|
||||
collector.on("collect", async i => {
|
||||
if (i.isButton()) {
|
||||
if (i.customId === "clips_prev_page") {
|
||||
i.deferUpdate();
|
||||
|
||||
const resource = createAudioResource(fs.createReadStream(`./clips/${clip}.mp3`));
|
||||
const player = createAudioPlayer()
|
||||
.on("error", err => {
|
||||
connection.destroy();
|
||||
console.error(err.message);
|
||||
if (currentPage !== 0) {
|
||||
--currentPage;
|
||||
interaction.editReply({
|
||||
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
|
||||
embeds: [embeds[currentPage]],
|
||||
components: [row]
|
||||
});
|
||||
}
|
||||
} else if (i.customId === "clips_next_page") {
|
||||
i.deferUpdate();
|
||||
|
||||
if (currentPage < embeds.length - 1) {
|
||||
currentPage++;
|
||||
interaction.editReply({
|
||||
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
|
||||
embeds: [embeds[currentPage]],
|
||||
components: [row]
|
||||
});
|
||||
}
|
||||
} else if (i.customId === "clips_jump_page") {
|
||||
i.deferUpdate();
|
||||
|
||||
const msg = await interaction.followUp({
|
||||
content: interaction.translate("misc:JUMP_TO_PAGE", {
|
||||
length: embeds.length
|
||||
}),
|
||||
fetchReply: true
|
||||
});
|
||||
|
||||
player.play(resource);
|
||||
connection.subscribe(player);
|
||||
const filter = res => {
|
||||
return res.author.id === interaction.user.id && !isNaN(res.content);
|
||||
};
|
||||
|
||||
player.on(AudioPlayerStatus.Idle, () => {
|
||||
connection.destroy();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
interaction.channel.awaitMessages({ filter, max: 1, time: (10 * 1000) }).then(collected => {
|
||||
if (embeds[collected.first().content - 1]) {
|
||||
currentPage = collected.first().content - 1;
|
||||
interaction.editReply({
|
||||
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
|
||||
embeds: [embeds[currentPage]],
|
||||
components: [row]
|
||||
});
|
||||
|
||||
if (collected.first().deletable) collected.first().delete();
|
||||
if (msg.deletable) msg.delete();
|
||||
} else {
|
||||
if (collected.first().deletable) collected.first().delete();
|
||||
if (msg.deletable) msg.delete();
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else if (i.customId === "clips_stop") {
|
||||
i.deferUpdate();
|
||||
collector.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await interaction.editReply({
|
||||
content: interaction.translate("music/clips:PLAYING", {
|
||||
clip
|
||||
}),
|
||||
components: []
|
||||
collector.on("end", () => {
|
||||
row.components.forEach(component => {
|
||||
component.setDisabled(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
collector.on("end", () => {
|
||||
return interaction.editReply({
|
||||
return interaction.editReply({
|
||||
components: [row]
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const voice = interaction.member.voice.channel;
|
||||
if (!voice) return interaction.editReply({ content: interaction.translate("music/play:NO_VOICE_CHANNEL") });
|
||||
const queue = client.player.getQueue(interaction.guild.id);
|
||||
if (queue) return interaction.editReply({ content: interaction.translate("music/clips:ACTIVE_QUEUE") });
|
||||
if (getVoiceConnection(interaction.guild.id)) return interaction.editReply({ content: interaction.translate("music/clips:ACTIVE_CLIP") });
|
||||
if (!fs.existsSync(`./clips/${query}.mp3`)) return interaction.editReply({ content: interaction.translate("music/clips:NO_FILE", { file: query }) });
|
||||
|
||||
try {
|
||||
const connection = joinVoiceChannel({
|
||||
channelId: voice.id,
|
||||
guildId: interaction.guild.id,
|
||||
adapterCreator: interaction.guild.voiceAdapterCreator
|
||||
});
|
||||
|
||||
const resource = createAudioResource(fs.createReadStream(`./clips/${query}.mp3`));
|
||||
const player = createAudioPlayer()
|
||||
.on("error", err => {
|
||||
connection.destroy();
|
||||
console.error(err.message);
|
||||
});
|
||||
|
||||
player.play(resource);
|
||||
connection.subscribe(player);
|
||||
|
||||
player.on(AudioPlayerStatus.Idle, () => {
|
||||
connection.destroy();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
await interaction.editReply({
|
||||
content: interaction.translate("music/clips:PLAYING", {
|
||||
clip: query
|
||||
}),
|
||||
components: []
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("discord.js").ChatInputCommandInteraction} interaction
|
||||
* @param {Array} clips
|
||||
* @returns
|
||||
*/
|
||||
function generateClipsEmbeds(interaction, clips) {
|
||||
const embeds = [];
|
||||
let k = 10;
|
||||
|
||||
for (let i = 0; i < clips.length; i += 10) {
|
||||
const current = clips.slice(i, k);
|
||||
k += 10;
|
||||
|
||||
const page = current.join("\n");
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(interaction.client.config.embed.color)
|
||||
.setFooter({
|
||||
text: interaction.client.config.embed.footer
|
||||
})
|
||||
.setTitle(interaction.translate("music/clips:CLIPS_LIST"))
|
||||
.setDescription(page)
|
||||
.setTimestamp();
|
||||
embeds.push(embed);
|
||||
}
|
||||
|
||||
return embeds;
|
||||
}
|
||||
|
||||
module.exports = Clips;
|
|
@ -1,5 +1,5 @@
|
|||
const { SlashCommandBuilder, ActionRowBuilder, SelectMenuBuilder } = require("discord.js"),
|
||||
{ QueueRepeatMode } = require("../../helpers/Music/dist/index");
|
||||
const { SlashCommandBuilder } = require("discord.js"),
|
||||
{ QueueRepeatMode } = require("discord-player-play-dl");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
class Loop extends BaseCommand {
|
||||
|
@ -11,10 +11,19 @@ class Loop extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("loop")
|
||||
.setDescription(client.translate("music/loop:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/loop:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("option")
|
||||
.setDescription(client.translate("economy/bank:OPTION"))
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{ name: client.translate("music/loop:AUTOPLAY"), value: "3" },
|
||||
{ name: client.translate("music/loop:QUEUE"), value: "2" },
|
||||
{ name: client.translate("music/loop:TRACK"), value: "1" },
|
||||
{ name: client.translate("music/loop:DISABLE"), value: "0" }
|
||||
)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -32,64 +41,23 @@ class Loop extends BaseCommand {
|
|||
* @param {Object} data
|
||||
*/
|
||||
async execute(client, interaction) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const voice = interaction.member.voice.channel;
|
||||
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL");
|
||||
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
|
||||
const queue = client.player.getQueue(interaction.guildId);
|
||||
if (!queue) return interaction.error("music/play:NOT_PLAYING");
|
||||
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
|
||||
|
||||
const row = new ActionRowBuilder()
|
||||
.addComponents(
|
||||
new SelectMenuBuilder()
|
||||
.setCustomId("loop_select")
|
||||
.setPlaceholder(client.translate("common:NOTHING_SELECTED"))
|
||||
.addOptions([
|
||||
{
|
||||
label: client.translate("music/loop:AUTOPLAY"),
|
||||
value: "3"
|
||||
},
|
||||
{
|
||||
label: client.translate("music/loop:QUEUE"),
|
||||
value: "2"
|
||||
},
|
||||
{
|
||||
label: client.translate("music/loop:TRACK"),
|
||||
value: "1"
|
||||
},
|
||||
{
|
||||
label: client.translate("music/loop:DISABLE"),
|
||||
value: "0"
|
||||
}
|
||||
])
|
||||
);
|
||||
const type = interaction.options.getString("option");
|
||||
const mode = type === "3" ? QueueRepeatMode.AUTOPLAY :
|
||||
type === "2" ? QueueRepeatMode.QUEUE :
|
||||
type === "1" ? QueueRepeatMode.TRACK : QueueRepeatMode.OFF;
|
||||
|
||||
await interaction.editReply({
|
||||
content: interaction.translate("common:AVAILABLE_OPTIONS"),
|
||||
components: [row]
|
||||
});
|
||||
queue.setRepeatMode(mode);
|
||||
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (15 * 1000) });
|
||||
|
||||
collector.on("collect", async i => {
|
||||
if (i.isSelectMenu() && i.customId === "loop_select") {
|
||||
const type = i?.values[0];
|
||||
const mode = type === "3" ? QueueRepeatMode.AUTOPLAY :
|
||||
type === "2" ? QueueRepeatMode.QUEUE :
|
||||
type === "1" ? QueueRepeatMode.TRACK : QueueRepeatMode.OFF;
|
||||
|
||||
queue.setRepeatMode(mode);
|
||||
return interaction.editReply({
|
||||
content: interaction.translate(`music/loop:${
|
||||
type === "3" ? "AUTOPLAY_ENABLED" :
|
||||
type === "2" ? "QUEUE_ENABLED" :
|
||||
type === "1" ? "TRACK_ENABLED" : "LOOP_DISABLED"
|
||||
}`),
|
||||
components: []
|
||||
});
|
||||
}
|
||||
});
|
||||
interaction.success(`music/loop:${
|
||||
type === "3" ? "AUTOPLAY_ENABLED" :
|
||||
type === "2" ? "QUEUE_ENABLED" :
|
||||
type === "1" ? "TRACK_ENABLED" : "LOOP_DISABLED"
|
||||
}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"),
|
||||
{ QueueRepeatMode } = require("../../helpers/Music/dist/index");
|
||||
{ QueueRepeatMode } = require("discord-player-play-dl");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
class Nowplaying extends BaseCommand {
|
||||
|
@ -11,10 +11,10 @@ class Nowplaying extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("nowplaying")
|
||||
.setDescription(client.translate("music/nowplaying:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/nowplaying:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -33,8 +33,9 @@ class Nowplaying extends BaseCommand {
|
|||
*/
|
||||
async execute(client, interaction) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const queue = client.player.getQueue(interaction.guildId);
|
||||
if (!queue) return interaction.error("music/play:NOT_PLAYING");
|
||||
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
|
||||
const progressBar = queue.createProgressBar();
|
||||
const track = queue.current;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField } = require("discord.js"),
|
||||
{ QueryType } = require("../../helpers/Music/dist/index");
|
||||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionsBitField } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
class Play extends BaseCommand {
|
||||
|
@ -12,12 +11,12 @@ class Play extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("play")
|
||||
.setDescription(client.translate("music/play:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("query")
|
||||
.setDescription(client.translate("music/play:QUERY"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -38,40 +37,18 @@ class Play extends BaseCommand {
|
|||
await interaction.deferReply();
|
||||
|
||||
const voice = interaction.member.voice.channel;
|
||||
if (!voice) return interaction.editReply({ content: interaction.translate("music/play:NO_VOICE_CHANNEL") });
|
||||
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
|
||||
const query = interaction.options.getString("query");
|
||||
const perms = voice.permissionsFor(client.user);
|
||||
if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.editReply({ content: interaction.translate("music/play:VOICE_CHANNEL_CONNECT") });
|
||||
if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true });
|
||||
|
||||
try {
|
||||
var searchResult;
|
||||
if (!query.includes("http")) {
|
||||
const search = await playdl.search(query, { limit: 10 });
|
||||
var searchResult = await client.player.search(query, {
|
||||
requestedBy: interaction.user
|
||||
});
|
||||
|
||||
if (search) {
|
||||
const found = search.map(track => new Track(client.player, {
|
||||
title: track.title,
|
||||
duration: Util.buildTimeCode(Util.parseMS(track.durationInSec * 1000)),
|
||||
thumbnail: track.thumbnails[0].url || "https://cdn.discordapp.com/attachments/708642702602010684/1012418217660121089/noimage.png",
|
||||
views: track.views,
|
||||
author: track.channel.name,
|
||||
description: "search",
|
||||
url: track.url,
|
||||
requestedBy: interaction.user,
|
||||
playlist: null,
|
||||
source: "youtube"
|
||||
}));
|
||||
|
||||
searchResult = { playlist: null, tracks: found, searched: true };
|
||||
}
|
||||
} else {
|
||||
searchResult = await client.player.search(query, {
|
||||
requestedBy: interaction.user
|
||||
});
|
||||
|
||||
if (!searchResult.tracks[0] || !searchResult)
|
||||
return interaction.editReply({ content: interaction.translate("music/play:NO_RESULT", { query, error: "Unknown Error" }) });
|
||||
}
|
||||
if (!searchResult.tracks[0] || !searchResult)
|
||||
return interaction.error("music/play:NO_RESULT", { query, error: "Скорее всего видео заблокировано по региону" }, { edit: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return interaction.editReply({
|
||||
|
@ -87,7 +64,7 @@ class Play extends BaseCommand {
|
|||
autoSelfDeaf: true,
|
||||
leaveOnEnd: true,
|
||||
leaveOnStop: true,
|
||||
bufferingTimeout: 1000,
|
||||
bufferingTimeout: 1000
|
||||
});
|
||||
|
||||
if (searchResult.searched) {
|
||||
|
@ -215,7 +192,7 @@ class Play extends BaseCommand {
|
|||
components: [row1, row2, row3]
|
||||
});
|
||||
|
||||
collector.end();
|
||||
collector.stop();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"),
|
||||
{ QueueRepeatMode } = require("../../helpers/Music/dist/index");
|
||||
{ QueueRepeatMode } = require("discord-player-play-dl");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
class Queue extends BaseCommand {
|
||||
|
@ -11,10 +11,10 @@ class Queue extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("queue")
|
||||
.setDescription(client.translate("music/queue:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/queue:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class Queue extends BaseCommand {
|
|||
if (embeds != generateQueueEmbeds(interaction, queue)) embeds = generateQueueEmbeds(interaction, queue);
|
||||
|
||||
const msg = await interaction.followUp({
|
||||
content: interaction.translate("music/queue:PAGE_TO_JUMP", {
|
||||
content: interaction.translate("misc:JUMP_TO_PAGE", {
|
||||
length: embeds.length
|
||||
}),
|
||||
fetchReply: true
|
||||
|
@ -151,7 +151,7 @@ class Queue extends BaseCommand {
|
|||
/**
|
||||
*
|
||||
* @param {import("discord.js").ChatInputCommandInteraction} interaction
|
||||
* @param {import("../../helpers/Music/dist/index").Queue} queue
|
||||
* @param {import("discord-player-play-dl").Queue} queue
|
||||
* @returns
|
||||
*/
|
||||
function generateQueueEmbeds(interaction, queue) {
|
||||
|
|
44
commands/Music/shuffle.js
Normal file
44
commands/Music/shuffle.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
const { SlashCommandBuilder } = require("discord.js");
|
||||
const BaseCommand = require("../../base/BaseCommand");
|
||||
|
||||
class Shuffle extends BaseCommand {
|
||||
/**
|
||||
*
|
||||
* @param {import("../base/JaBa")} client
|
||||
*/
|
||||
constructor(client) {
|
||||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("shuffle")
|
||||
.setDescription(client.translate("music/shuffle:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {import("../../base/JaBa")} client
|
||||
*/
|
||||
async onLoad() {
|
||||
//...
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {import("../../base/JaBa")} client
|
||||
* @param {import("discord.js").ChatInputCommandInteraction} interaction
|
||||
* @param {Object} data
|
||||
*/
|
||||
async execute(client, interaction) {
|
||||
const voice = interaction.member.voice.channel;
|
||||
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { ephemeral: true });
|
||||
const queue = client.player.getQueue(interaction.guildId);
|
||||
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true });
|
||||
|
||||
const shuffled = queue.shuffle();
|
||||
if (shuffled) interaction.success("music/shuffle:SUCCESS");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Shuffle;
|
|
@ -10,10 +10,10 @@ class Skip extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("skip")
|
||||
.setDescription(client.translate("music/skip:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/skip:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class Skipto extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("skipto")
|
||||
.setDescription(client.translate("music/skipto:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addIntegerOption(option => option.setName("position")
|
||||
.setDescription(client.translate("music/skipto:POSITION"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Stop extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("stop")
|
||||
.setDescription(client.translate("music/stop:DESCRIPTION")),
|
||||
.setDescription(client.translate("music/stop:DESCRIPTION"))
|
||||
.setDMPermission(false),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ class NSFW extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("nsfw")
|
||||
.setDescription(client.translate("nsfw/nsfw:DESCRIPTION")),
|
||||
.setDescription(client.translate("nsfw/nsfw:DESCRIPTION"))
|
||||
.setDMPermission(true),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: false
|
||||
});
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class NSFW extends BaseCommand {
|
|||
async execute(client, interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
if (!interaction.channel.nsfw) return interaction.replyT("misc:NSFW_COMMAND", null, { ephemeral: true, edit: true });
|
||||
if ((interaction.guildId && !interaction.channel.nsfw)) return interaction.replyT("misc:NSFW_COMMAND", null, { ephemeral: true, edit: true });
|
||||
|
||||
const tags = ["hentai", "ecchi", "lewdanimegirls", "hentaifemdom", "animefeets", "animebooty", "biganimetiddies", "sideoppai", "ahegao"].map(tag =>
|
||||
JSON.parse(JSON.stringify({
|
||||
|
@ -51,14 +51,15 @@ class NSFW extends BaseCommand {
|
|||
.addOptions(tags)
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
const msg = await interaction.editReply({
|
||||
content: interaction.translate("common:AVAILABLE_OPTIONS"),
|
||||
ephemeral: true,
|
||||
fetchReply: true,
|
||||
components: [row]
|
||||
});
|
||||
|
||||
const filter = i => i.user.id === interaction.user.id;
|
||||
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: (2 * 60 * 1000) });
|
||||
const collector = msg.createMessageComponentCollector({ filter, idle: (2 * 60 * 1000) });
|
||||
|
||||
collector.on("collect", async i => {
|
||||
if (i.isSelectMenu() && i.customId === "nsfw_select") {
|
||||
|
|
|
@ -11,6 +11,7 @@ class Announcement extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("announcement")
|
||||
.setDescription(client.translate("owner/announcement:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("message")
|
||||
.setDescription(client.translate("common:MESSAGE"))
|
||||
.setRequired(true))
|
||||
|
@ -19,7 +20,6 @@ class Announcement extends BaseCommand {
|
|||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Debug extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("debug")
|
||||
.setDescription(client.translate("owner/debug:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addSubcommand(subcommand => subcommand.setName("set")
|
||||
.setDescription(client.translate("owner/debug:SET"))
|
||||
.addStringOption(option => option.setName("type")
|
||||
|
@ -51,7 +52,6 @@ class Debug extends BaseCommand {
|
|||
),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class Debug extends BaseCommand {
|
|||
* @param {import("discord.js").ChatInputCommandInteraction} interaction
|
||||
* @param {Array} data
|
||||
*/
|
||||
async execute(client, interaction,) {
|
||||
async execute(client, interaction) {
|
||||
const command = interaction.options.getSubcommand();
|
||||
|
||||
if (command === "set") {
|
||||
|
@ -79,7 +79,8 @@ class Debug extends BaseCommand {
|
|||
id: member.id
|
||||
});
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id
|
||||
id: member.id,
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
const int = interaction.options.getInteger("int");
|
||||
|
||||
|
@ -137,7 +138,8 @@ class Debug extends BaseCommand {
|
|||
id: member.id
|
||||
});
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id
|
||||
id: member.id,
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
const int = interaction.options.getInteger("int");
|
||||
|
||||
|
|
|
@ -11,12 +11,12 @@ class Eval extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("eval")
|
||||
.setDescription(client.translate("owner/eval:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("code")
|
||||
.setDescription(client.translate("owner/eval:CODE"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ class Reload extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("reload")
|
||||
.setDescription(client.translate("owner/reload:DESCRIPTION"))
|
||||
.setDMPermission(true)
|
||||
.addStringOption(option => option.setName("command")
|
||||
.setDescription(client.translate("owner/reload:COMMAND"))
|
||||
.setRequired(true)),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ class Say extends BaseCommand {
|
|||
command: new SlashCommandBuilder()
|
||||
.setName("say")
|
||||
.setDescription(client.translate("owner/say:DESCRIPTION"))
|
||||
.setDMPermission(false)
|
||||
.addStringOption(option => option.setName("message")
|
||||
.setDescription(client.translate("common:MESSAGE"))
|
||||
.setRequired(true))
|
||||
|
@ -18,7 +19,6 @@ class Say extends BaseCommand {
|
|||
.setDescription(client.translate("common:CHANNEL"))),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ class Servers extends BaseCommand {
|
|||
super({
|
||||
command: new SlashCommandBuilder()
|
||||
.setName("servers")
|
||||
.setDescription(client.translate("owner/servers:DESCRIPTION")),
|
||||
.setDescription(client.translate("owner/servers:DESCRIPTION"))
|
||||
.setDMPermission(true),
|
||||
aliases: [],
|
||||
dirname: __dirname,
|
||||
guildOnly: true,
|
||||
ownerOnly: true
|
||||
});
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ class Servers extends BaseCommand {
|
|||
i.deferUpdate();
|
||||
|
||||
const msg = await interaction.followUp({
|
||||
content: interaction.translate("music/queue:PAGE_TO_JUMP", {
|
||||
content: interaction.translate("misc:JUMP_TO_PAGE", {
|
||||
length: embeds.length
|
||||
}),
|
||||
fetchReply: true
|
||||
|
@ -142,7 +142,7 @@ class Servers extends BaseCommand {
|
|||
/**
|
||||
*
|
||||
* @param {import("discord.js").ChatInputCommandInteraction} interaction
|
||||
* @param {*} servers
|
||||
* @param {Array} servers
|
||||
* @returns
|
||||
*/
|
||||
function generateServersEmbeds(interaction, servers) {
|
||||
|
@ -150,7 +150,7 @@ function generateServersEmbeds(interaction, servers) {
|
|||
let k = 10;
|
||||
|
||||
for (let i = 0; i < servers.size; i += 10) {
|
||||
const current = servers.map(g => g).slice(i, k).sort((a, b) => b.memberCount - a.memberCount);
|
||||
const current = servers.sort((a, b) => b.memberCount - a.memberCount).map(g => g).slice(i, k);
|
||||
let j = i;
|
||||
k += 10;
|
||||
|
||||
|
@ -170,12 +170,4 @@ function generateServersEmbeds(interaction, servers) {
|
|||
return embeds;
|
||||
}
|
||||
|
||||
// `${interaction.translate("common:SERVERS")}: ${interaction.client.guilds.cache.size}\n\n` +
|
||||
// interaction.client.guilds.cache
|
||||
// .sort((a, b) => b.memberCount - a.memberCount)
|
||||
// .map(g => g)
|
||||
// .map((g, i) => `${i + 1}. ${g.name} | ${g.memberCount} ${interaction.client.getNoun(g.memberCount, interaction.translate("misc:NOUNS:MEMBERS:1"), interaction.translate("misc:NOUNS:MEMBERS:2"), interaction.translate("misc:NOUNS:MEMBERS:5"))}`)
|
||||
// .slice(i, k)
|
||||
// .join("\n")
|
||||
|
||||
module.exports = Servers;
|
|
@ -3,9 +3,9 @@ module.exports = {
|
|||
token: "XXXXXXXXXXX",
|
||||
/* ID of Bot's user */
|
||||
user: "XXXXXXXXXXX",
|
||||
/* For the support server */
|
||||
/* Set to true for production */
|
||||
production: true,
|
||||
/* For the support server */
|
||||
support: {
|
||||
id: "XXXXXXXXXXX", // The ID of the support server
|
||||
logs: "XXXXXXXXXXX", // And the ID of the logs channel of your server (new servers for example)
|
||||
|
|
|
@ -1,3 +1,63 @@
|
|||
### JaBa v4.1.13
|
||||
* Изменения
|
||||
* Переписана команда *clips*.
|
||||
|
||||
### JaBa v4.1.12
|
||||
* Исправления
|
||||
* Фикс поиска по ссылкам.
|
||||
* Фикс воспроизведения с SoundCloud.
|
||||
|
||||
### JaBa v4.1.11
|
||||
* Изменения
|
||||
* Команды которые нельзя использовать в ЛС с ботом не будут там отображаться.
|
||||
|
||||
* Исправления
|
||||
* Переписаны команды *nsfw* и *memes* для работы в ЛС с ботом.
|
||||
|
||||
### JaBa v4.1.10
|
||||
* Добавлено
|
||||
* Команда *shuffle* - Перемешать очередь.
|
||||
|
||||
* Изменения
|
||||
* Многие команды теперь можно использовать в ЛС с ботом. Узнать где именно можно использовать команду через *help*.
|
||||
|
||||
### JaBa v4.1.9
|
||||
* Изменения
|
||||
* Переписана система опыта. Теперь при достижении нового уровня опыт сбрасывается и бот оповещает о получении нового уровня.
|
||||
|
||||
* Исправления
|
||||
* Команды *set* и *debug* ничего не делали.
|
||||
|
||||
### JaBa v4.1.8
|
||||
* Добавлено
|
||||
* Возможность сразу сократить ссылку в команде *lmgtfy*.
|
||||
|
||||
* Изменения
|
||||
* Переписаны подсказки к командам.
|
||||
* Переписана команда *giveaway*.
|
||||
|
||||
* Исправления
|
||||
* Фикс ошибки *shorturl* с некоторыми ссылками.
|
||||
|
||||
### JaBa v4.1.7
|
||||
* Изменения
|
||||
* Переписана команда *leaderboard*.
|
||||
|
||||
### JaBa v4.1.6
|
||||
* Изменения
|
||||
* Изменён способ указания типа повтора в *loop*. Теперь вы указываете тип аргументом (подсказки имеются), а не из выпадающего списка в отдельном сообщении. Это одновременно удобно, быстро и меньше кода =)
|
||||
|
||||
* Исправления
|
||||
* Фиксы в *tictactoe*.
|
||||
|
||||
### JaBa v4.1.5
|
||||
* Изменения
|
||||
* Более подробные сообщения в *remindme*.
|
||||
|
||||
### JaBa v4.1.4
|
||||
* Исправления
|
||||
* Ошибки в clips, loop, nowplaying и play.
|
||||
|
||||
### JaBa v4.1.3
|
||||
* Добавлено
|
||||
* Возможность принудительной очистки транзакций с помощью *transactions clear:True*
|
||||
|
|
|
@ -17,7 +17,7 @@ router.get("/:serverID", CheckAuth, async(req, res) => {
|
|||
|
||||
// Fetch guild informations
|
||||
const guildInfos = await utils.fetchGuild(guild.id, req.client, req.user.guilds);
|
||||
const memberData = await req.client.findOrCreateMember({ id: req.userInfos.id, guildID: guild.id });
|
||||
const memberData = await req.client.findOrCreateMember({ id: req.userInfos.id, guildId: guild.id });
|
||||
|
||||
res.render("manager/guild", {
|
||||
guild: guildInfos,
|
||||
|
|
|
@ -14,7 +14,7 @@ router.get("/:serverID", CheckAuth, async (req, res) => {
|
|||
});
|
||||
}
|
||||
|
||||
const memberData = await req.client.findOrCreateMember({ id: req.userInfos.id, guildID: guild.id });
|
||||
const memberData = await req.client.findOrCreateMember({ id: req.userInfos.id, guildId: guild.id });
|
||||
|
||||
// Fetch guild informations
|
||||
const membersData = await req.client.membersData.find({
|
||||
|
|
|
@ -26,7 +26,7 @@ class CommandHandler extends BaseEvent {
|
|||
data.userData = userData;
|
||||
|
||||
if (command.guildOnly && !interaction.inGuild()) return interaction.replyT("misc:GUILD_ONLY", { ephemeral: true });
|
||||
if (command.ownerOnly && interaction.member.id !== client.config.owner.id) return interaction.replyT("misc:OWNER_ONLY", { ephemeral: true });
|
||||
if (command.ownerOnly && interaction.user.id !== client.config.owner.id) return interaction.replyT("misc:OWNER_ONLY", { ephemeral: true });
|
||||
|
||||
if (interaction.inGuild()) {
|
||||
const guildData = await client.findOrCreateGuild({
|
||||
|
@ -36,7 +36,7 @@ class CommandHandler extends BaseEvent {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: interaction.member.id,
|
||||
guildID: interaction.guildId
|
||||
guildId: interaction.guildId
|
||||
});
|
||||
data.memberData = memberData;
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ class CommandHandler extends BaseEvent {
|
|||
userData.achievements.firstCommand.achieved = true;
|
||||
userData.markModified("achievements.firstCommand");
|
||||
await userData.save();
|
||||
await interaction.followUp({
|
||||
await interaction.channel.send({
|
||||
content: interaction.user.toString(),
|
||||
files: [{
|
||||
name: "achievement_unlocked2.png",
|
||||
attachment: "./assets/img/achievements/achievement_unlocked2.png"
|
||||
|
|
|
@ -40,7 +40,7 @@ class GuildMemberAdd extends BaseEvent {
|
|||
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: member.id,
|
||||
guildID: member.guild.id
|
||||
guildId: member.guild.id
|
||||
});
|
||||
if (memberData.mute.muted && memberData.mute.endDate > Date.now()) {
|
||||
member.guild.channels.cache.forEach((channel) => {
|
||||
|
|
|
@ -33,7 +33,7 @@ class MessageCreate extends BaseEvent {
|
|||
if (message.guild) {
|
||||
const memberData = await client.findOrCreateMember({
|
||||
id: message.author.id,
|
||||
guildID: message.guild.id
|
||||
guildId: message.guild.id
|
||||
});
|
||||
data.memberData = memberData;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ class MessageCreate extends BaseEvent {
|
|||
await data.userData.save();
|
||||
message.replyT("general/afk:DELETED", {
|
||||
username: message.author.username
|
||||
});
|
||||
}, { mention: true });
|
||||
}
|
||||
|
||||
message.mentions.users.forEach(async (u) => {
|
||||
|
@ -75,24 +75,37 @@ class MessageCreate extends BaseEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../base/JaBa")} client
|
||||
* @param {import("discord.js").Message} msg
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
async function updateXp(client, msg, data) {
|
||||
const points = parseInt(data.memberData.exp);
|
||||
const level = parseInt(data.memberData.level);
|
||||
const isInCooldown = xpCooldown[msg.author.id];
|
||||
const points = parseInt(data.memberData.exp),
|
||||
level = parseInt(data.memberData.level),
|
||||
isInCooldown = xpCooldown[msg.author.id];
|
||||
|
||||
if (isInCooldown) {
|
||||
if (isInCooldown > Date.now()) return;
|
||||
}
|
||||
|
||||
const toWait = Date.now() + 60000; // 1 min
|
||||
const toWait = Date.now() + (60 * 1000); // 1 min
|
||||
xpCooldown[msg.author.id] = toWait;
|
||||
|
||||
const won = client.functions.randomNum(1, 4);
|
||||
const won = client.functions.randomNum(1, 2);
|
||||
const newXp = parseInt(points + won, 10);
|
||||
const neededXp = 5 * (level * level) + 80 * level + 100;
|
||||
|
||||
if (newXp > neededXp) data.memberData.level = parseInt(level + 1, 10);
|
||||
if (newXp > neededXp) {
|
||||
data.memberData.level = parseInt(level + 1, 10);
|
||||
data.memberData.exp = 0;
|
||||
msg.replyT("misc:LEVEL_UP", {
|
||||
level: data.memberData.level
|
||||
}, { mention: false });
|
||||
} else data.memberData.exp = parseInt(newXp, 10);
|
||||
|
||||
data.memberData.exp = parseInt(newXp, 10);
|
||||
await data.memberData.save();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,31 +18,24 @@ class Ready extends BaseEvent {
|
|||
let tUsers = client.users.cache.size - hiddenGuild.memberCount;
|
||||
let tServers = client.guilds.cache.size - 1;
|
||||
|
||||
// Logs some informations using logger
|
||||
client.logger.log(`Loaded a total of ${commands.length} command(s).`, "ready");
|
||||
client.logger.log(`${client.user.tag}, ready to serve ${tUsers} users in ${tServers} servers.`, "ready");
|
||||
client.logger.log(`Invite Link: ${client.generateInvite({ scopes: ["bot", "applications.commands"] , permissions: [ PermissionsBitField.Flags.Administrator ] })}`, "ready");
|
||||
|
||||
// Birthday Announce
|
||||
const birthdays = require("../helpers/birthdays");
|
||||
birthdays.init(client);
|
||||
|
||||
// Unmute users
|
||||
const checkUnmutes = require("../helpers/checkUnmutes");
|
||||
checkUnmutes.init(client);
|
||||
|
||||
// Send reminds
|
||||
const checkReminds = require("../helpers/checkReminds");
|
||||
checkReminds.init(client);
|
||||
|
||||
// Clear transactions
|
||||
const cleanup = require("../helpers/cleanup");
|
||||
cleanup.init(client);
|
||||
|
||||
// Start the dashboard
|
||||
if (client.config.dashboard.enabled) client.dashboard.init(client);
|
||||
|
||||
// Update status
|
||||
const version = require("../package.json").version;
|
||||
const status = [
|
||||
{ name: "help", type: ActivityType.Watching },
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
node_modules/
|
||||
dist/
|
||||
|
||||
*.d.ts
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/ban-ts-comment": "error",
|
||||
"semi": "error",
|
||||
"no-console": "error"
|
||||
}
|
||||
}
|
96
helpers/Music/dist/Player.d.ts
vendored
96
helpers/Music/dist/Player.d.ts
vendored
|
@ -1,96 +0,0 @@
|
|||
import { Client, Collection, GuildResolvable } from "discord.js";
|
||||
import { TypedEmitter as EventEmitter } from "tiny-typed-emitter";
|
||||
import { Queue } from "./Structures/Queue";
|
||||
import { VoiceUtils } from "./VoiceInterface/VoiceUtils";
|
||||
import { PlayerEvents, PlayerOptions, SearchOptions, PlayerInitOptions, PlayerSearchResult, PlaylistInitData } from "./types/types";
|
||||
import Track from "./Structures/Track";
|
||||
import { Playlist } from "./Structures/Playlist";
|
||||
import { ExtractorModel } from "./Structures/ExtractorModel";
|
||||
declare class Player extends EventEmitter<PlayerEvents> {
|
||||
readonly client: Client;
|
||||
readonly options: PlayerInitOptions;
|
||||
readonly queues: Collection<string, Queue<unknown>>;
|
||||
readonly voiceUtils: VoiceUtils;
|
||||
readonly extractors: Collection<string, ExtractorModel>;
|
||||
requiredEvents: string[];
|
||||
/**
|
||||
* Creates new Discord Player
|
||||
* @param {Client} client The Discord Client
|
||||
* @param {PlayerInitOptions} [options] The player init options
|
||||
*/
|
||||
constructor(client: Client, options?: PlayerInitOptions);
|
||||
/**
|
||||
* Handles voice state update
|
||||
* @param {VoiceState} oldState The old voice state
|
||||
* @param {VoiceState} newState The new voice state
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
private _handleVoiceState;
|
||||
/**
|
||||
* Creates a queue for a guild if not available, else returns existing queue
|
||||
* @param {GuildResolvable} guild The guild
|
||||
* @param {PlayerOptions} queueInitOptions Queue init options
|
||||
* @returns {Queue}
|
||||
*/
|
||||
createQueue<T = unknown>(guild: GuildResolvable, queueInitOptions?: PlayerOptions & {
|
||||
metadata?: T;
|
||||
}): Queue<T>;
|
||||
/**
|
||||
* Returns the queue if available
|
||||
* @param {GuildResolvable} guild The guild id
|
||||
* @returns {Queue}
|
||||
*/
|
||||
getQueue<T = unknown>(guild: GuildResolvable): Queue<T>;
|
||||
/**
|
||||
* Deletes a queue and returns deleted queue object
|
||||
* @param {GuildResolvable} guild The guild id to remove
|
||||
* @returns {Queue}
|
||||
*/
|
||||
deleteQueue<T = unknown>(guild: GuildResolvable): Queue<T>;
|
||||
/**
|
||||
* @typedef {object} PlayerSearchResult
|
||||
* @property {Playlist} [playlist] The playlist (if any)
|
||||
* @property {Track[]} tracks The tracks
|
||||
*/
|
||||
/**
|
||||
* Search tracks
|
||||
* @param {string|Track} query The search query
|
||||
* @param {SearchOptions} options The search options
|
||||
* @returns {Promise<PlayerSearchResult>}
|
||||
*/
|
||||
search(query: string | Track, options: SearchOptions): Promise<PlayerSearchResult>;
|
||||
/**
|
||||
* Registers extractor
|
||||
* @param {string} extractorName The extractor name
|
||||
* @param {ExtractorModel|any} extractor The extractor object
|
||||
* @param {boolean} [force=false] Overwrite existing extractor with this name (if available)
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
use(extractorName: string, extractor: ExtractorModel | any, force?: boolean): ExtractorModel;
|
||||
/**
|
||||
* Removes registered extractor
|
||||
* @param {string} extractorName The extractor name
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
unuse(extractorName: string): ExtractorModel;
|
||||
/**
|
||||
* Generates a report of the dependencies used by the `@discordjs/voice` module. Useful for debugging.
|
||||
* @returns {string}
|
||||
*/
|
||||
scanDeps(): string;
|
||||
emit<U extends keyof PlayerEvents>(eventName: U, ...args: Parameters<PlayerEvents[U]>): boolean;
|
||||
/**
|
||||
* Resolves queue
|
||||
* @param {GuildResolvable|Queue} queueLike Queue like object
|
||||
* @returns {Queue}
|
||||
*/
|
||||
resolveQueue<T>(queueLike: GuildResolvable | Queue): Queue<T>;
|
||||
[Symbol.iterator](): Generator<Queue<unknown>, void, undefined>;
|
||||
/**
|
||||
* Creates `Playlist` instance
|
||||
* @param data The data to initialize a playlist
|
||||
*/
|
||||
createPlaylist(data: PlaylistInitData): Playlist;
|
||||
}
|
||||
export { Player };
|
579
helpers/Music/dist/Player.js
vendored
579
helpers/Music/dist/Player.js
vendored
|
@ -1,579 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Player = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const discord_js_1 = require("discord.js");
|
||||
const tiny_typed_emitter_1 = require("tiny-typed-emitter");
|
||||
const Queue_1 = require("./Structures/Queue");
|
||||
const VoiceUtils_1 = require("./VoiceInterface/VoiceUtils");
|
||||
const types_1 = require("./types/types");
|
||||
const Track_1 = tslib_1.__importDefault(require("./Structures/Track"));
|
||||
const play_dl_1 = tslib_1.__importDefault(require("play-dl"));
|
||||
const spotify_url_info_1 = tslib_1.__importDefault(require("spotify-url-info"));
|
||||
const QueryResolver_1 = require("./utils/QueryResolver");
|
||||
const Util_1 = require("./utils/Util");
|
||||
const PlayerError_1 = require("./Structures/PlayerError");
|
||||
const Playlist_1 = require("./Structures/Playlist");
|
||||
const ExtractorModel_1 = require("./Structures/ExtractorModel");
|
||||
const voice_1 = require("@discordjs/voice");
|
||||
class Player extends tiny_typed_emitter_1.TypedEmitter {
|
||||
/**
|
||||
* Creates new Discord Player
|
||||
* @param {Client} client The Discord Client
|
||||
* @param {PlayerInitOptions} [options] The player init options
|
||||
*/
|
||||
constructor(client, options = {}) {
|
||||
super();
|
||||
this.options = {
|
||||
autoRegisterExtractor: true,
|
||||
connectionTimeout: 20000
|
||||
};
|
||||
this.queues = new discord_js_1.Collection();
|
||||
this.voiceUtils = new VoiceUtils_1.VoiceUtils();
|
||||
this.extractors = new discord_js_1.Collection();
|
||||
this.requiredEvents = ["error", "connectionError"];
|
||||
/**
|
||||
* The discord.js client
|
||||
* @type {Client}
|
||||
*/
|
||||
this.client = client;
|
||||
if (this.client?.options?.intents && !new discord_js_1.IntentsBitField(this.client?.options?.intents).has(discord_js_1.IntentsBitField.Flags.GuildVoiceStates)) {
|
||||
throw new PlayerError_1.PlayerError('client is missing "GuildVoiceStates" intent');
|
||||
}
|
||||
/**
|
||||
* The extractors collection
|
||||
* @type {ExtractorModel}
|
||||
*/
|
||||
this.options = Object.assign(this.options, options);
|
||||
this.client.on("voiceStateUpdate", this._handleVoiceState.bind(this));
|
||||
if (this.options?.autoRegisterExtractor) {
|
||||
let nv; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
if ((nv = Util_1.Util.require("@discord-player/extractor"))) {
|
||||
["Attachment", "Facebook", "Reverbnation", "Vimeo"].forEach((ext) => void this.use(ext, nv[ext]));
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles voice state update
|
||||
* @param {VoiceState} oldState The old voice state
|
||||
* @param {VoiceState} newState The new voice state
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_handleVoiceState(oldState, newState) {
|
||||
const queue = this.getQueue(oldState.guild.id);
|
||||
if (!queue || !queue.connection)
|
||||
return;
|
||||
if (oldState.channelId && !newState.channelId && newState.member.id === newState.guild.members.me.id) {
|
||||
try {
|
||||
queue.destroy();
|
||||
}
|
||||
catch {
|
||||
/* noop */
|
||||
}
|
||||
return void this.emit("botDisconnect", queue);
|
||||
}
|
||||
if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.members.me.id) {
|
||||
if (!oldState.serverMute && newState.serverMute) {
|
||||
// state.serverMute can be null
|
||||
queue.setPaused(!!newState.serverMute);
|
||||
}
|
||||
else if (!oldState.suppress && newState.suppress) {
|
||||
// state.suppress can be null
|
||||
queue.setPaused(!!newState.suppress);
|
||||
if (newState.suppress) {
|
||||
newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldState.channelId === newState.channelId && newState.member.id === newState.guild.members.me.id) {
|
||||
if (!oldState.serverMute && newState.serverMute) {
|
||||
// state.serverMute can be null
|
||||
queue.setPaused(!!newState.serverMute);
|
||||
}
|
||||
else if (!oldState.suppress && newState.suppress) {
|
||||
// state.suppress can be null
|
||||
queue.setPaused(!!newState.suppress);
|
||||
if (newState.suppress) {
|
||||
newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queue.connection && !newState.channelId && oldState.channelId === queue.connection.channel.id) {
|
||||
if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
|
||||
return;
|
||||
const timeout = setTimeout(() => {
|
||||
if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
|
||||
return;
|
||||
if (!this.queues.has(queue.guild.id))
|
||||
return;
|
||||
if (queue.options.leaveOnEmpty)
|
||||
queue.destroy(true);
|
||||
this.emit("channelEmpty", queue);
|
||||
}, queue.options.leaveOnEmptyCooldown || 0).unref();
|
||||
queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
|
||||
}
|
||||
if (queue.connection && newState.channelId && newState.channelId === queue.connection.channel.id) {
|
||||
const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
|
||||
const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
|
||||
if (!channelEmpty && emptyTimeout) {
|
||||
clearTimeout(emptyTimeout);
|
||||
queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
|
||||
}
|
||||
}
|
||||
if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId && newState.member.id === newState.guild.members.me.id) {
|
||||
if (queue.connection && newState.member.id === newState.guild.members.me.id)
|
||||
queue.connection.channel = newState.channel;
|
||||
const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
|
||||
const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
|
||||
if (!channelEmpty && emptyTimeout) {
|
||||
clearTimeout(emptyTimeout);
|
||||
queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
|
||||
}
|
||||
else {
|
||||
const timeout = setTimeout(() => {
|
||||
if (queue.connection && !Util_1.Util.isVoiceEmpty(queue.connection.channel))
|
||||
return;
|
||||
if (!this.queues.has(queue.guild.id))
|
||||
return;
|
||||
if (queue.options.leaveOnEmpty)
|
||||
queue.destroy(true);
|
||||
this.emit("channelEmpty", queue);
|
||||
}, queue.options.leaveOnEmptyCooldown || 0).unref();
|
||||
queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a queue for a guild if not available, else returns existing queue
|
||||
* @param {GuildResolvable} guild The guild
|
||||
* @param {PlayerOptions} queueInitOptions Queue init options
|
||||
* @returns {Queue}
|
||||
*/
|
||||
createQueue(guild, queueInitOptions = {}) {
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
if (!guild)
|
||||
throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
|
||||
if (this.queues.has(guild.id))
|
||||
return this.queues.get(guild.id);
|
||||
const _meta = queueInitOptions.metadata;
|
||||
delete queueInitOptions["metadata"];
|
||||
queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = 0.08);
|
||||
const queue = new Queue_1.Queue(this, guild, queueInitOptions);
|
||||
queue.metadata = _meta;
|
||||
this.queues.set(guild.id, queue);
|
||||
return queue;
|
||||
}
|
||||
/**
|
||||
* Returns the queue if available
|
||||
* @param {GuildResolvable} guild The guild id
|
||||
* @returns {Queue}
|
||||
*/
|
||||
getQueue(guild) {
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
if (!guild)
|
||||
throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
|
||||
return this.queues.get(guild.id);
|
||||
}
|
||||
/**
|
||||
* Deletes a queue and returns deleted queue object
|
||||
* @param {GuildResolvable} guild The guild id to remove
|
||||
* @returns {Queue}
|
||||
*/
|
||||
deleteQueue(guild) {
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
if (!guild)
|
||||
throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
|
||||
const prev = this.getQueue(guild);
|
||||
try {
|
||||
prev.destroy();
|
||||
}
|
||||
catch { } // eslint-disable-line no-empty
|
||||
this.queues.delete(guild.id);
|
||||
return prev;
|
||||
}
|
||||
/**
|
||||
* @typedef {object} PlayerSearchResult
|
||||
* @property {Playlist} [playlist] The playlist (if any)
|
||||
* @property {Track[]} tracks The tracks
|
||||
*/
|
||||
/**
|
||||
* Search tracks
|
||||
* @param {string|Track} query The search query
|
||||
* @param {SearchOptions} options The search options
|
||||
* @returns {Promise<PlayerSearchResult>}
|
||||
*/
|
||||
async search(query, options) {
|
||||
if (query instanceof Track_1.default)
|
||||
return { playlist: query.playlist || null, tracks: [query] };
|
||||
if (!options)
|
||||
throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
|
||||
options.requestedBy = this.client.users.resolve(options.requestedBy);
|
||||
if (!("searchEngine" in options))
|
||||
options.searchEngine = types_1.QueryType.AUTO;
|
||||
if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
|
||||
const extractor = this.extractors.get(options.searchEngine);
|
||||
if (!extractor.validate(query))
|
||||
return { playlist: null, tracks: [] };
|
||||
const data = await extractor.handle(query);
|
||||
if (data && data.data.length) {
|
||||
const playlist = !data.playlist
|
||||
? null
|
||||
: new Playlist_1.Playlist(this, {
|
||||
...data.playlist,
|
||||
tracks: []
|
||||
});
|
||||
const tracks = data.data.map((m) => new Track_1.default(this, {
|
||||
...m,
|
||||
requestedBy: options.requestedBy,
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
|
||||
playlist: playlist
|
||||
}));
|
||||
if (playlist)
|
||||
playlist.tracks = tracks;
|
||||
return { playlist: playlist, tracks: tracks };
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for (const [_, extractor] of this.extractors) {
|
||||
if (options.blockExtractor)
|
||||
break;
|
||||
if (!extractor.validate(query))
|
||||
continue;
|
||||
const data = await extractor.handle(query);
|
||||
if (data && data.data.length) {
|
||||
const playlist = !data.playlist
|
||||
? null
|
||||
: new Playlist_1.Playlist(this, {
|
||||
...data.playlist,
|
||||
tracks: []
|
||||
});
|
||||
const tracks = data.data.map((m) => new Track_1.default(this, {
|
||||
...m,
|
||||
requestedBy: options.requestedBy,
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
|
||||
playlist: playlist
|
||||
}));
|
||||
if (playlist)
|
||||
playlist.tracks = tracks;
|
||||
return { playlist: playlist, tracks: tracks };
|
||||
}
|
||||
}
|
||||
const qt = options.searchEngine === types_1.QueryType.AUTO ? await QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
|
||||
switch (qt) {
|
||||
case types_1.QueryType.YOUTUBE_VIDEO: {
|
||||
const info = await play_dl_1.default.video_info(query).catch(Util_1.Util.noop);
|
||||
if (!info)
|
||||
return { playlist: null, tracks: [] };
|
||||
const track = new Track_1.default(this, {
|
||||
title: info.video_details.title,
|
||||
description: info.video_details.description,
|
||||
author: info.video_details.channel?.name,
|
||||
url: info.video_details.url,
|
||||
requestedBy: options.requestedBy,
|
||||
thumbnail: Util_1.Util.last(info.video_details.thumbnails)?.url,
|
||||
views: info.video_details.views || 0,
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(info.video_details.durationInSec * 1000)),
|
||||
source: "youtube",
|
||||
raw: info
|
||||
});
|
||||
return { playlist: null, tracks: [track] };
|
||||
}
|
||||
case types_1.QueryType.YOUTUBE_SEARCH: {
|
||||
const videos = await play_dl_1.default.search(query, {
|
||||
limit: 10,
|
||||
source: { youtube: "video" }
|
||||
}).catch(Util_1.Util.noop);
|
||||
if (!videos)
|
||||
return { playlist: null, tracks: [] };
|
||||
const tracks = videos.map(m => {
|
||||
m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
return new Track_1.default(this, {
|
||||
title: m.title,
|
||||
description: m.description,
|
||||
author: m.channel?.name,
|
||||
url: m.url,
|
||||
requestedBy: options.requestedBy,
|
||||
thumbnail: Util_1.Util.last(m.thumbnails).url,
|
||||
views: m.views,
|
||||
duration: m.durationRaw,
|
||||
source: "youtube",
|
||||
raw: m
|
||||
});
|
||||
});
|
||||
return { playlist: null, tracks, searched: true };
|
||||
}
|
||||
case types_1.QueryType.SOUNDCLOUD_TRACK:
|
||||
case types_1.QueryType.SOUNDCLOUD_SEARCH: {
|
||||
const result = await QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : await play_dl_1.default.search(query, {
|
||||
limit: 5,
|
||||
source: { soundcloud: "tracks" }
|
||||
}).catch(() => []);
|
||||
if (!result || !result.length)
|
||||
return { playlist: null, tracks: [] };
|
||||
const res = [];
|
||||
for (const r of result) {
|
||||
const trackInfo = await play_dl_1.default.soundcloud(r.url).catch(Util_1.Util.noop);
|
||||
if (!trackInfo)
|
||||
continue;
|
||||
const track = new Track_1.default(this, {
|
||||
title: trackInfo.name,
|
||||
url: trackInfo.url,
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.durationInMs)),
|
||||
description: "",
|
||||
thumbnail: trackInfo.user.thumbnail,
|
||||
views: 0,
|
||||
author: trackInfo.user.name,
|
||||
requestedBy: options.requestedBy,
|
||||
source: "soundcloud",
|
||||
engine: trackInfo
|
||||
});
|
||||
res.push(track);
|
||||
}
|
||||
return { playlist: null, tracks: res };
|
||||
}
|
||||
case types_1.QueryType.SPOTIFY_SONG: {
|
||||
const spotifyData = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
|
||||
.getData(query)
|
||||
.catch(Util_1.Util.noop);
|
||||
if (!spotifyData)
|
||||
return { playlist: null, tracks: [] };
|
||||
const spotifyTrack = new Track_1.default(this, {
|
||||
title: spotifyData.name,
|
||||
description: spotifyData.description ?? "",
|
||||
author: spotifyData.artists[0]?.name ?? "Unknown Artist",
|
||||
url: spotifyData.external_urls?.spotify ?? query,
|
||||
thumbnail: spotifyData.album?.images[0]?.url ?? spotifyData.preview_url?.length
|
||||
? `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}`
|
||||
: "https://www.scdn.co/i/_global/twitter_card-default.jpg",
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms)),
|
||||
views: 0,
|
||||
requestedBy: options.requestedBy,
|
||||
source: "spotify"
|
||||
});
|
||||
return { playlist: null, tracks: [spotifyTrack] };
|
||||
}
|
||||
case types_1.QueryType.SPOTIFY_PLAYLIST:
|
||||
case types_1.QueryType.SPOTIFY_ALBUM: {
|
||||
const spotifyPlaylist = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
|
||||
.getData(query)
|
||||
.catch(Util_1.Util.noop);
|
||||
if (!spotifyPlaylist)
|
||||
return { playlist: null, tracks: [] };
|
||||
const playlist = new Playlist_1.Playlist(this, {
|
||||
title: spotifyPlaylist.name ?? spotifyPlaylist.title,
|
||||
description: spotifyPlaylist.description ?? "",
|
||||
thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
|
||||
type: spotifyPlaylist.type,
|
||||
source: "spotify",
|
||||
author: spotifyPlaylist.type !== "playlist"
|
||||
? {
|
||||
name: spotifyPlaylist.artists[0]?.name ?? "Unknown Artist",
|
||||
url: spotifyPlaylist.artists[0]?.external_urls?.spotify ?? null
|
||||
}
|
||||
: {
|
||||
name: spotifyPlaylist.owner?.display_name ?? spotifyPlaylist.owner?.id ?? "Unknown Artist",
|
||||
url: spotifyPlaylist.owner?.external_urls?.spotify ?? null
|
||||
},
|
||||
tracks: [],
|
||||
id: spotifyPlaylist.id,
|
||||
url: spotifyPlaylist.external_urls?.spotify ?? query,
|
||||
rawPlaylist: spotifyPlaylist
|
||||
});
|
||||
if (spotifyPlaylist.type !== "playlist") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
|
||||
const data = new Track_1.default(this, {
|
||||
title: m.name ?? "",
|
||||
description: m.description ?? "",
|
||||
author: m.artists[0]?.name ?? "Unknown Artist",
|
||||
url: m.external_urls?.spotify ?? query,
|
||||
thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
|
||||
views: 0,
|
||||
requestedBy: options.requestedBy,
|
||||
playlist,
|
||||
source: "spotify"
|
||||
});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
|
||||
const data = new Track_1.default(this, {
|
||||
title: m.track.name ?? "",
|
||||
description: m.track.description ?? "",
|
||||
author: m.track.artists?.[0]?.name ?? "Unknown Artist",
|
||||
url: m.track.external_urls?.spotify ?? query,
|
||||
thumbnail: m.track.album?.images?.[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
|
||||
views: 0,
|
||||
requestedBy: options.requestedBy,
|
||||
playlist,
|
||||
source: "spotify"
|
||||
});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
return { playlist: playlist, tracks: playlist.tracks };
|
||||
}
|
||||
case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
|
||||
const data = await play_dl_1.default.soundcloud(query).catch(Util_1.Util.noop);
|
||||
if (!data)
|
||||
return { playlist: null, tracks: [] };
|
||||
const res = new Playlist_1.Playlist(this, {
|
||||
title: data.name,
|
||||
description: "",
|
||||
thumbnail: "https://soundcloud.com/pwa-icon-192.png",
|
||||
type: "playlist",
|
||||
source: "soundcloud",
|
||||
author: {
|
||||
name: data.user.name ?? "Unknown Owner",
|
||||
url: data.user.url
|
||||
},
|
||||
tracks: [],
|
||||
id: `${data.id}`,
|
||||
url: data.url,
|
||||
rawPlaylist: data
|
||||
});
|
||||
const songs = await data.all_tracks();
|
||||
for (const song of songs) {
|
||||
const track = new Track_1.default(this, {
|
||||
title: song.name,
|
||||
description: "",
|
||||
author: song.publisher.name ?? "Unknown Publisher",
|
||||
url: song.url,
|
||||
thumbnail: song.thumbnail,
|
||||
duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.durationInMs)),
|
||||
views: 0,
|
||||
requestedBy: options.requestedBy,
|
||||
playlist: res,
|
||||
source: "soundcloud",
|
||||
engine: song
|
||||
});
|
||||
res.tracks.push(track);
|
||||
}
|
||||
return { playlist: res, tracks: res.tracks };
|
||||
}
|
||||
case types_1.QueryType.YOUTUBE_PLAYLIST: {
|
||||
const ytpl = await play_dl_1.default.playlist_info(query, { incomplete: true }).catch(Util_1.Util.noop);
|
||||
if (!ytpl)
|
||||
return { playlist: null, tracks: [] };
|
||||
const playlist = new Playlist_1.Playlist(this, {
|
||||
title: ytpl.title,
|
||||
thumbnail: ytpl.thumbnail,
|
||||
description: "",
|
||||
type: "playlist",
|
||||
source: "youtube",
|
||||
author: {
|
||||
name: ytpl.channel.name,
|
||||
url: ytpl.channel.url
|
||||
},
|
||||
tracks: [],
|
||||
id: ytpl.id,
|
||||
url: ytpl.url,
|
||||
rawPlaylist: ytpl
|
||||
});
|
||||
const videos = await ytpl.all_videos();
|
||||
playlist.tracks = videos.map(video => new Track_1.default(this, {
|
||||
title: video.title,
|
||||
description: video.description,
|
||||
author: video.channel?.name,
|
||||
url: video.url,
|
||||
requestedBy: options.requestedBy,
|
||||
thumbnail: Util_1.Util.last(video.thumbnails).url,
|
||||
views: video.views,
|
||||
duration: video.durationRaw,
|
||||
raw: video,
|
||||
playlist: playlist,
|
||||
source: "youtube"
|
||||
}));
|
||||
return { playlist: playlist, tracks: playlist.tracks };
|
||||
}
|
||||
default:
|
||||
return { playlist: null, tracks: [] };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Registers extractor
|
||||
* @param {string} extractorName The extractor name
|
||||
* @param {ExtractorModel|any} extractor The extractor object
|
||||
* @param {boolean} [force=false] Overwrite existing extractor with this name (if available)
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
use(extractorName, extractor, force = false) {
|
||||
if (!extractorName)
|
||||
throw new PlayerError_1.PlayerError("Cannot use unknown extractor!", PlayerError_1.ErrorStatusCode.UNKNOWN_EXTRACTOR);
|
||||
if (this.extractors.has(extractorName) && !force)
|
||||
return this.extractors.get(extractorName);
|
||||
if (extractor instanceof ExtractorModel_1.ExtractorModel) {
|
||||
this.extractors.set(extractorName, extractor);
|
||||
return extractor;
|
||||
}
|
||||
for (const method of ["validate", "getInfo"]) {
|
||||
if (typeof extractor[method] !== "function")
|
||||
throw new PlayerError_1.PlayerError("Invalid extractor data!", PlayerError_1.ErrorStatusCode.INVALID_EXTRACTOR);
|
||||
}
|
||||
const model = new ExtractorModel_1.ExtractorModel(extractorName, extractor);
|
||||
this.extractors.set(model.name, model);
|
||||
return model;
|
||||
}
|
||||
/**
|
||||
* Removes registered extractor
|
||||
* @param {string} extractorName The extractor name
|
||||
* @returns {ExtractorModel}
|
||||
*/
|
||||
unuse(extractorName) {
|
||||
if (!this.extractors.has(extractorName))
|
||||
throw new PlayerError_1.PlayerError(`Cannot find extractor "${extractorName}"`, PlayerError_1.ErrorStatusCode.UNKNOWN_EXTRACTOR);
|
||||
const prev = this.extractors.get(extractorName);
|
||||
this.extractors.delete(extractorName);
|
||||
return prev;
|
||||
}
|
||||
/**
|
||||
* Generates a report of the dependencies used by the `@discordjs/voice` module. Useful for debugging.
|
||||
* @returns {string}
|
||||
*/
|
||||
scanDeps() {
|
||||
const line = "-".repeat(50);
|
||||
const depsReport = (0, voice_1.generateDependencyReport)();
|
||||
const extractorReport = this.extractors
|
||||
.map((m) => {
|
||||
return `${m.name} :: ${m.version || "0.1.0"}`;
|
||||
})
|
||||
.join("\n");
|
||||
return `${depsReport}\n${line}\nLoaded Extractors:\n${extractorReport || "None"}`;
|
||||
}
|
||||
emit(eventName, ...args) {
|
||||
if (this.requiredEvents.includes(eventName) && !super.eventNames().includes(eventName)) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(...args);
|
||||
process.emitWarning(`[DiscordPlayerWarning] Unhandled "${eventName}" event! Events ${this.requiredEvents.map((m) => `"${m}"`).join(", ")} must have event listeners!`);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return super.emit(eventName, ...args);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Resolves queue
|
||||
* @param {GuildResolvable|Queue} queueLike Queue like object
|
||||
* @returns {Queue}
|
||||
*/
|
||||
resolveQueue(queueLike) {
|
||||
return this.getQueue(queueLike instanceof Queue_1.Queue ? queueLike.guild : queueLike);
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
yield* Array.from(this.queues.values());
|
||||
}
|
||||
/**
|
||||
* Creates `Playlist` instance
|
||||
* @param data The data to initialize a playlist
|
||||
*/
|
||||
createPlaylist(data) {
|
||||
return new Playlist_1.Playlist(this, data);
|
||||
}
|
||||
}
|
||||
exports.Player = Player;
|
|
@ -1,29 +0,0 @@
|
|||
import { ExtractorModelData } from "../types/types";
|
||||
declare class ExtractorModel {
|
||||
name: string;
|
||||
private _raw;
|
||||
/**
|
||||
* Model for raw Discord Player extractors
|
||||
* @param {string} extractorName Name of the extractor
|
||||
* @param {object} data Extractor object
|
||||
*/
|
||||
constructor(extractorName: string, data: any);
|
||||
/**
|
||||
* Method to handle requests from `Player.play()`
|
||||
* @param {string} query Query to handle
|
||||
* @returns {Promise<ExtractorModelData>}
|
||||
*/
|
||||
handle(query: string): Promise<ExtractorModelData>;
|
||||
/**
|
||||
* Method used by Discord Player to validate query with this extractor
|
||||
* @param {string} query The query to validate
|
||||
* @returns {boolean}
|
||||
*/
|
||||
validate(query: string): boolean;
|
||||
/**
|
||||
* The extractor version
|
||||
* @type {string}
|
||||
*/
|
||||
get version(): string;
|
||||
}
|
||||
export { ExtractorModel };
|
65
helpers/Music/dist/Structures/ExtractorModel.js
vendored
65
helpers/Music/dist/Structures/ExtractorModel.js
vendored
|
@ -1,65 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ExtractorModel = void 0;
|
||||
class ExtractorModel {
|
||||
/**
|
||||
* Model for raw Discord Player extractors
|
||||
* @param {string} extractorName Name of the extractor
|
||||
* @param {object} data Extractor object
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
constructor(extractorName, data) {
|
||||
/**
|
||||
* The extractor name
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = extractorName;
|
||||
/**
|
||||
* The raw model
|
||||
* @name ExtractorModel#_raw
|
||||
* @type {any}
|
||||
* @private
|
||||
*/
|
||||
Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
|
||||
}
|
||||
/**
|
||||
* Method to handle requests from `Player.play()`
|
||||
* @param {string} query Query to handle
|
||||
* @returns {Promise<ExtractorModelData>}
|
||||
*/
|
||||
async handle(query) {
|
||||
const data = await this._raw.getInfo(query);
|
||||
if (!data)
|
||||
return null;
|
||||
return {
|
||||
playlist: data.playlist ?? null,
|
||||
data: data.info?.map((m) => ({
|
||||
title: m.title,
|
||||
duration: m.duration,
|
||||
thumbnail: m.thumbnail,
|
||||
engine: m.engine,
|
||||
views: m.views,
|
||||
author: m.author,
|
||||
description: m.description,
|
||||
url: m.url,
|
||||
source: m.source || "arbitrary"
|
||||
})) ?? []
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Method used by Discord Player to validate query with this extractor
|
||||
* @param {string} query The query to validate
|
||||
* @returns {boolean}
|
||||
*/
|
||||
validate(query) {
|
||||
return Boolean(this._raw.validate(query));
|
||||
}
|
||||
/**
|
||||
* The extractor version
|
||||
* @type {string}
|
||||
*/
|
||||
get version() {
|
||||
return this._raw.version ?? "0.0.0";
|
||||
}
|
||||
}
|
||||
exports.ExtractorModel = ExtractorModel;
|
31
helpers/Music/dist/Structures/PlayerError.d.ts
vendored
31
helpers/Music/dist/Structures/PlayerError.d.ts
vendored
|
@ -1,31 +0,0 @@
|
|||
export declare enum ErrorStatusCode {
|
||||
STREAM_ERROR = "StreamError",
|
||||
AUDIO_PLAYER_ERROR = "AudioPlayerError",
|
||||
PLAYER_ERROR = "PlayerError",
|
||||
NO_AUDIO_RESOURCE = "NoAudioResource",
|
||||
UNKNOWN_GUILD = "UnknownGuild",
|
||||
INVALID_ARG_TYPE = "InvalidArgType",
|
||||
UNKNOWN_EXTRACTOR = "UnknownExtractor",
|
||||
INVALID_EXTRACTOR = "InvalidExtractor",
|
||||
INVALID_CHANNEL_TYPE = "InvalidChannelType",
|
||||
INVALID_TRACK = "InvalidTrack",
|
||||
UNKNOWN_REPEAT_MODE = "UnknownRepeatMode",
|
||||
TRACK_NOT_FOUND = "TrackNotFound",
|
||||
NO_CONNECTION = "NoConnection",
|
||||
DESTROYED_QUEUE = "DestroyedQueue"
|
||||
}
|
||||
export declare class PlayerError extends Error {
|
||||
message: string;
|
||||
statusCode: ErrorStatusCode;
|
||||
createdAt: Date;
|
||||
constructor(message: string, code?: ErrorStatusCode);
|
||||
get createdTimestamp(): number;
|
||||
valueOf(): ErrorStatusCode;
|
||||
toJSON(): {
|
||||
stack: string;
|
||||
code: ErrorStatusCode;
|
||||
message: string;
|
||||
created: number;
|
||||
};
|
||||
toString(): string;
|
||||
}
|
48
helpers/Music/dist/Structures/PlayerError.js
vendored
48
helpers/Music/dist/Structures/PlayerError.js
vendored
|
@ -1,48 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PlayerError = exports.ErrorStatusCode = void 0;
|
||||
var ErrorStatusCode;
|
||||
(function (ErrorStatusCode) {
|
||||
ErrorStatusCode["STREAM_ERROR"] = "StreamError";
|
||||
ErrorStatusCode["AUDIO_PLAYER_ERROR"] = "AudioPlayerError";
|
||||
ErrorStatusCode["PLAYER_ERROR"] = "PlayerError";
|
||||
ErrorStatusCode["NO_AUDIO_RESOURCE"] = "NoAudioResource";
|
||||
ErrorStatusCode["UNKNOWN_GUILD"] = "UnknownGuild";
|
||||
ErrorStatusCode["INVALID_ARG_TYPE"] = "InvalidArgType";
|
||||
ErrorStatusCode["UNKNOWN_EXTRACTOR"] = "UnknownExtractor";
|
||||
ErrorStatusCode["INVALID_EXTRACTOR"] = "InvalidExtractor";
|
||||
ErrorStatusCode["INVALID_CHANNEL_TYPE"] = "InvalidChannelType";
|
||||
ErrorStatusCode["INVALID_TRACK"] = "InvalidTrack";
|
||||
ErrorStatusCode["UNKNOWN_REPEAT_MODE"] = "UnknownRepeatMode";
|
||||
ErrorStatusCode["TRACK_NOT_FOUND"] = "TrackNotFound";
|
||||
ErrorStatusCode["NO_CONNECTION"] = "NoConnection";
|
||||
ErrorStatusCode["DESTROYED_QUEUE"] = "DestroyedQueue";
|
||||
})(ErrorStatusCode = exports.ErrorStatusCode || (exports.ErrorStatusCode = {}));
|
||||
class PlayerError extends Error {
|
||||
constructor(message, code = ErrorStatusCode.PLAYER_ERROR) {
|
||||
super();
|
||||
this.createdAt = new Date();
|
||||
this.message = `[${code}] ${message}`;
|
||||
this.statusCode = code;
|
||||
this.name = code;
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
get createdTimestamp() {
|
||||
return this.createdAt.getTime();
|
||||
}
|
||||
valueOf() {
|
||||
return this.statusCode;
|
||||
}
|
||||
toJSON() {
|
||||
return {
|
||||
stack: this.stack,
|
||||
code: this.statusCode,
|
||||
message: this.message,
|
||||
created: this.createdTimestamp
|
||||
};
|
||||
}
|
||||
toString() {
|
||||
return this.stack;
|
||||
}
|
||||
}
|
||||
exports.PlayerError = PlayerError;
|
33
helpers/Music/dist/Structures/Playlist.d.ts
vendored
33
helpers/Music/dist/Structures/Playlist.d.ts
vendored
|
@ -1,33 +0,0 @@
|
|||
import { Player } from "../Player";
|
||||
import { Track } from "./Track";
|
||||
import { PlaylistInitData, PlaylistJSON, TrackSource } from "../types/types";
|
||||
declare class Playlist {
|
||||
readonly player: Player;
|
||||
tracks: Track[];
|
||||
title: string;
|
||||
description: string;
|
||||
thumbnail: string;
|
||||
type: "album" | "playlist";
|
||||
source: TrackSource;
|
||||
author: {
|
||||
name: string;
|
||||
url: string;
|
||||
};
|
||||
id: string;
|
||||
url: string;
|
||||
readonly rawPlaylist?: any;
|
||||
/**
|
||||
* Playlist constructor
|
||||
* @param {Player} player The player
|
||||
* @param {PlaylistInitData} data The data
|
||||
*/
|
||||
constructor(player: Player, data: PlaylistInitData);
|
||||
[Symbol.iterator](): Generator<Track, void, undefined>;
|
||||
/**
|
||||
* JSON representation of this playlist
|
||||
* @param {boolean} [withTracks=true] If it should build json with tracks
|
||||
* @returns {PlaylistJSON}
|
||||
*/
|
||||
toJSON(withTracks?: boolean): PlaylistJSON;
|
||||
}
|
||||
export { Playlist };
|
108
helpers/Music/dist/Structures/Playlist.js
vendored
108
helpers/Music/dist/Structures/Playlist.js
vendored
|
@ -1,108 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Playlist = void 0;
|
||||
class Playlist {
|
||||
/**
|
||||
* Playlist constructor
|
||||
* @param {Player} player The player
|
||||
* @param {PlaylistInitData} data The data
|
||||
*/
|
||||
constructor(player, data) {
|
||||
/**
|
||||
* The player
|
||||
* @name Playlist#player
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
/**
|
||||
* The tracks in this playlist
|
||||
* @name Playlist#tracks
|
||||
* @type {Track[]}
|
||||
*/
|
||||
this.tracks = data.tracks ?? [];
|
||||
/**
|
||||
* The author of this playlist
|
||||
* @name Playlist#author
|
||||
* @type {object}
|
||||
*/
|
||||
this.author = data.author;
|
||||
/**
|
||||
* The description
|
||||
* @name Playlist#description
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = data.description;
|
||||
/**
|
||||
* The thumbnail of this playlist
|
||||
* @name Playlist#thumbnail
|
||||
* @type {string}
|
||||
*/
|
||||
this.thumbnail = data.thumbnail;
|
||||
/**
|
||||
* The playlist type:
|
||||
* - `album`
|
||||
* - `playlist`
|
||||
* @name Playlist#type
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = data.type;
|
||||
/**
|
||||
* The source of this playlist:
|
||||
* - `youtube`
|
||||
* - `soundcloud`
|
||||
* - `spotify`
|
||||
* - `arbitrary`
|
||||
* @name Playlist#source
|
||||
* @type {string}
|
||||
*/
|
||||
this.source = data.source;
|
||||
/**
|
||||
* The playlist id
|
||||
* @name Playlist#id
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id;
|
||||
/**
|
||||
* The playlist url
|
||||
* @name Playlist#url
|
||||
* @type {string}
|
||||
*/
|
||||
this.url = data.url;
|
||||
/**
|
||||
* The playlist title
|
||||
* @type {string}
|
||||
*/
|
||||
this.title = data.title;
|
||||
/**
|
||||
* @name Playlist#rawPlaylist
|
||||
* @type {any}
|
||||
* @readonly
|
||||
*/
|
||||
}
|
||||
*[Symbol.iterator]() {
|
||||
yield* this.tracks;
|
||||
}
|
||||
/**
|
||||
* JSON representation of this playlist
|
||||
* @param {boolean} [withTracks=true] If it should build json with tracks
|
||||
* @returns {PlaylistJSON}
|
||||
*/
|
||||
toJSON(withTracks = true) {
|
||||
const payload = {
|
||||
id: this.id,
|
||||
url: this.url,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
thumbnail: this.thumbnail,
|
||||
type: this.type,
|
||||
source: this.source,
|
||||
author: this.author,
|
||||
tracks: []
|
||||
};
|
||||
if (withTracks)
|
||||
payload.tracks = this.tracks.map((m) => m.toJSON(true));
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
exports.Playlist = Playlist;
|
241
helpers/Music/dist/Structures/Queue.d.ts
vendored
241
helpers/Music/dist/Structures/Queue.d.ts
vendored
|
@ -1,241 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import { Collection, Guild, GuildChannelResolvable } from "discord.js";
|
||||
import { Player } from "../Player";
|
||||
import { StreamDispatcher } from "../VoiceInterface/StreamDispatcher";
|
||||
import Track from "./Track";
|
||||
import { PlayerOptions, PlayerProgressbarOptions, PlayOptions, QueueFilters, QueueRepeatMode, TrackSource } from "../types/types";
|
||||
import type { Readable } from "stream";
|
||||
declare class Queue<T = unknown> {
|
||||
#private;
|
||||
readonly guild: Guild;
|
||||
readonly player: Player;
|
||||
connection: StreamDispatcher;
|
||||
tracks: Track[];
|
||||
previousTracks: Track[];
|
||||
options: PlayerOptions;
|
||||
playing: boolean;
|
||||
metadata?: T;
|
||||
repeatMode: QueueRepeatMode;
|
||||
readonly id: string;
|
||||
private _streamTime;
|
||||
_cooldownsTimeout: Collection<string, NodeJS.Timeout>;
|
||||
private _activeFilters;
|
||||
private _filtersUpdate;
|
||||
onBeforeCreateStream: (track: Track, source: TrackSource, queue: Queue) => Promise<Readable | undefined>;
|
||||
/**
|
||||
* Queue constructor
|
||||
* @param {Player} player The player that instantiated this queue
|
||||
* @param {Guild} guild The guild that instantiated this queue
|
||||
* @param {PlayerOptions} [options] Player options for the queue
|
||||
*/
|
||||
constructor(player: Player, guild: Guild, options?: PlayerOptions);
|
||||
/**
|
||||
* Returns current track
|
||||
* @type {Track}
|
||||
*/
|
||||
get current(): Track;
|
||||
/**
|
||||
* If this queue is destroyed
|
||||
* @type {boolean}
|
||||
*/
|
||||
get destroyed(): boolean;
|
||||
/**
|
||||
* Returns current track
|
||||
* @returns {Track}
|
||||
*/
|
||||
nowPlaying(): Track;
|
||||
/**
|
||||
* Connects to a voice channel
|
||||
* @param {GuildChannelResolvable} channel The voice/stage channel
|
||||
* @returns {Promise<Queue>}
|
||||
*/
|
||||
connect(channel: GuildChannelResolvable): Promise<this>;
|
||||
/**
|
||||
* Destroys this queue
|
||||
* @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy
|
||||
* @returns {void}
|
||||
*/
|
||||
destroy(disconnect?: boolean): void;
|
||||
/**
|
||||
* Skips current track
|
||||
* @returns {boolean}
|
||||
*/
|
||||
skip(): boolean;
|
||||
/**
|
||||
* Adds single track to the queue
|
||||
* @param {Track} track The track to add
|
||||
* @returns {void}
|
||||
*/
|
||||
addTrack(track: Track): void;
|
||||
/**
|
||||
* Adds multiple tracks to the queue
|
||||
* @param {Track[]} tracks Array of tracks to add
|
||||
*/
|
||||
addTracks(tracks: Track[]): void;
|
||||
/**
|
||||
* Sets paused state
|
||||
* @param {boolean} paused The paused state
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setPaused(paused?: boolean): boolean;
|
||||
/**
|
||||
* Sets bitrate
|
||||
* @param {number|auto} bitrate bitrate to set
|
||||
* @returns {void}
|
||||
*/
|
||||
setBitrate(bitrate: number | "auto"): void;
|
||||
/**
|
||||
* Sets volume
|
||||
* @param {number} amount The volume amount
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setVolume(amount: number): boolean;
|
||||
/**
|
||||
* Sets repeat mode
|
||||
* @param {QueueRepeatMode} mode The repeat mode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setRepeatMode(mode: QueueRepeatMode): boolean;
|
||||
/**
|
||||
* The current volume amount
|
||||
* @type {number}
|
||||
*/
|
||||
get volume(): number;
|
||||
set volume(amount: number);
|
||||
/**
|
||||
* The stream time of this queue
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime(): number;
|
||||
set streamTime(time: number);
|
||||
/**
|
||||
* Returns enabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersEnabled(): (keyof QueueFilters)[];
|
||||
/**
|
||||
* Returns disabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersDisabled(): (keyof QueueFilters)[];
|
||||
/**
|
||||
* Sets filters
|
||||
* @param {QueueFilters} filters Queue filters
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
setFilters(filters?: QueueFilters): Promise<void>;
|
||||
/**
|
||||
* Seeks to the given time
|
||||
* @param {number} position The position
|
||||
* @returns {boolean}
|
||||
*/
|
||||
seek(position: number): Promise<boolean>;
|
||||
/**
|
||||
* Plays previous track
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
back(): Promise<void>;
|
||||
/**
|
||||
* Clear this queue
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* Stops the player
|
||||
* @returns {void}
|
||||
*/
|
||||
stop(): void;
|
||||
/**
|
||||
* Shuffles this queue
|
||||
* @returns {boolean}
|
||||
*/
|
||||
shuffle(): boolean;
|
||||
/**
|
||||
* Removes a track from the queue
|
||||
* @param {Track|string|number} track The track to remove
|
||||
* @returns {Track}
|
||||
*/
|
||||
remove(track: Track | string | number): Track;
|
||||
/**
|
||||
* Returns the index of the specified track. If found, returns the track index else returns -1.
|
||||
* @param {number|Track|string} track The track
|
||||
* @returns {number}
|
||||
*/
|
||||
getTrackPosition(track: number | Track | string): number;
|
||||
/**
|
||||
* Jumps to particular track
|
||||
* @param {Track|number} track The track
|
||||
* @returns {void}
|
||||
*/
|
||||
jump(track: Track | number): void;
|
||||
/**
|
||||
* Jumps to particular track, removing other tracks on the way
|
||||
* @param {Track|number} track The track
|
||||
* @returns {void}
|
||||
*/
|
||||
skipTo(track: Track | number): void;
|
||||
/**
|
||||
* Inserts the given track to specified index
|
||||
* @param {Track} track The track to insert
|
||||
* @param {number} [index=0] The index where this track should be
|
||||
*/
|
||||
insert(track: Track, index?: number): void;
|
||||
/**
|
||||
* @typedef {object} PlayerTimestamp
|
||||
* @property {string} current The current progress
|
||||
* @property {string} end The total time
|
||||
* @property {number} progress Progress in %
|
||||
*/
|
||||
/**
|
||||
* Returns player stream timestamp
|
||||
* @returns {PlayerTimestamp}
|
||||
*/
|
||||
getPlayerTimestamp(): {
|
||||
current: string;
|
||||
end: string;
|
||||
progress: number;
|
||||
};
|
||||
/**
|
||||
* Creates progress bar string
|
||||
* @param {PlayerProgressbarOptions} options The progress bar options
|
||||
* @returns {string}
|
||||
*/
|
||||
createProgressBar(options?: PlayerProgressbarOptions): string;
|
||||
/**
|
||||
* Total duration
|
||||
* @type {Number}
|
||||
*/
|
||||
get totalTime(): number;
|
||||
/**
|
||||
* Play stream in a voice/stage channel
|
||||
* @param {Track} [src] The track to play (if empty, uses first track from the queue)
|
||||
* @param {PlayOptions} [options] The options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
play(src?: Track, options?: PlayOptions): Promise<void>;
|
||||
/**
|
||||
* Private method to handle autoplay
|
||||
* @param {Track} track The source track to find its similar track for autoplay
|
||||
* @returns {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
private _handleAutoplay;
|
||||
[Symbol.iterator](): Generator<Track, void, undefined>;
|
||||
/**
|
||||
* JSON representation of this queue
|
||||
* @returns {object}
|
||||
*/
|
||||
toJSON(): {
|
||||
id: string;
|
||||
guild: string;
|
||||
voiceChannel: string;
|
||||
options: PlayerOptions;
|
||||
tracks: import("../types/types").TrackJSON[];
|
||||
};
|
||||
/**
|
||||
* String representation of this queue
|
||||
* @returns {string}
|
||||
*/
|
||||
toString(): string;
|
||||
}
|
||||
export { Queue };
|
761
helpers/Music/dist/Structures/Queue.js
vendored
761
helpers/Music/dist/Structures/Queue.js
vendored
|
@ -1,761 +0,0 @@
|
|||
"use strict";
|
||||
var _Queue_instances, _Queue_lastVolume, _Queue_destroyed, _Queue_watchDestroyed, _Queue_getBufferingTimeout;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Queue = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const discord_js_1 = require("discord.js");
|
||||
const Track_1 = tslib_1.__importDefault(require("./Track"));
|
||||
const types_1 = require("../types/types");
|
||||
const voice_1 = require("@discordjs/voice");
|
||||
const play_dl_1 = tslib_1.__importDefault(require("play-dl"));
|
||||
const Util_1 = require("../utils/Util");
|
||||
const AudioFilters_1 = tslib_1.__importDefault(require("../utils/AudioFilters"));
|
||||
const PlayerError_1 = require("./PlayerError");
|
||||
const FFmpegStream_1 = require("../utils/FFmpegStream");
|
||||
class Queue {
|
||||
/**
|
||||
* Queue constructor
|
||||
* @param {Player} player The player that instantiated this queue
|
||||
* @param {Guild} guild The guild that instantiated this queue
|
||||
* @param {PlayerOptions} [options] Player options for the queue
|
||||
*/
|
||||
constructor(player, guild, options = {}) {
|
||||
_Queue_instances.add(this);
|
||||
this.tracks = [];
|
||||
this.previousTracks = [];
|
||||
this.playing = false;
|
||||
this.metadata = null;
|
||||
this.repeatMode = 0;
|
||||
this.id = discord_js_1.SnowflakeUtil.generate().toString();
|
||||
this._streamTime = 0;
|
||||
this._cooldownsTimeout = new discord_js_1.Collection();
|
||||
this._activeFilters = []; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
this._filtersUpdate = false;
|
||||
_Queue_lastVolume.set(this, 0);
|
||||
_Queue_destroyed.set(this, false);
|
||||
this.onBeforeCreateStream = null;
|
||||
/**
|
||||
* The player that instantiated this queue
|
||||
* @type {Player}
|
||||
* @readonly
|
||||
*/
|
||||
this.player = player;
|
||||
/**
|
||||
* The guild that instantiated this queue
|
||||
* @type {Guild}
|
||||
* @readonly
|
||||
*/
|
||||
this.guild = guild;
|
||||
/**
|
||||
* The player options for this queue
|
||||
* @type {PlayerOptions}
|
||||
*/
|
||||
this.options = {};
|
||||
/**
|
||||
* Queue repeat mode
|
||||
* @type {QueueRepeatMode}
|
||||
* @name Queue#repeatMode
|
||||
*/
|
||||
/**
|
||||
* Queue metadata
|
||||
* @type {any}
|
||||
* @name Queue#metadata
|
||||
*/
|
||||
/**
|
||||
* Previous tracks
|
||||
* @type {Track[]}
|
||||
* @name Queue#previousTracks
|
||||
*/
|
||||
/**
|
||||
* Regular tracks
|
||||
* @type {Track[]}
|
||||
* @name Queue#tracks
|
||||
*/
|
||||
/**
|
||||
* The connection
|
||||
* @type {StreamDispatcher}
|
||||
* @name Queue#connection
|
||||
*/
|
||||
/**
|
||||
* The ID of this queue
|
||||
* @type {Snowflake}
|
||||
* @name Queue#id
|
||||
*/
|
||||
Object.assign(this.options, {
|
||||
leaveOnEnd: true,
|
||||
leaveOnStop: true,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 1000,
|
||||
autoSelfDeaf: true,
|
||||
ytdlOptions: {
|
||||
highWaterMark: 1 << 25
|
||||
},
|
||||
initialVolume: 100,
|
||||
bufferingTimeout: 3000,
|
||||
spotifyBridge: true,
|
||||
disableVolume: false
|
||||
}, options);
|
||||
if ("onBeforeCreateStream" in this.options)
|
||||
this.onBeforeCreateStream = this.options.onBeforeCreateStream;
|
||||
this.player.emit("debug", this, `Queue initialized:\n\n${this.player.scanDeps()}`);
|
||||
}
|
||||
/**
|
||||
* Returns current track
|
||||
* @type {Track}
|
||||
*/
|
||||
get current() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return this.connection.audioResource?.metadata ?? this.tracks[0];
|
||||
}
|
||||
/**
|
||||
* If this queue is destroyed
|
||||
* @type {boolean}
|
||||
*/
|
||||
get destroyed() {
|
||||
return tslib_1.__classPrivateFieldGet(this, _Queue_destroyed, "f");
|
||||
}
|
||||
/**
|
||||
* Returns current track
|
||||
* @returns {Track}
|
||||
*/
|
||||
nowPlaying() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return this.current;
|
||||
}
|
||||
/**
|
||||
* Connects to a voice channel
|
||||
* @param {GuildChannelResolvable} channel The voice/stage channel
|
||||
* @returns {Promise<Queue>}
|
||||
*/
|
||||
async connect(channel) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const _channel = this.guild.channels.resolve(channel);
|
||||
if (![discord_js_1.ChannelType.GuildStageVoice, discord_js_1.ChannelType.GuildVoice].includes(_channel?.type))
|
||||
throw new PlayerError_1.PlayerError(`Channel type must be GuildVoice or GuildStageVoice, got ${_channel?.type}!`, PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
|
||||
const connection = await this.player.voiceUtils.connect(_channel, {
|
||||
deaf: this.options.autoSelfDeaf
|
||||
});
|
||||
this.connection = connection;
|
||||
if (_channel.type === discord_js_1.ChannelType.GuildStageVoice) {
|
||||
await _channel.guild.members.me.voice.setSuppressed(false).catch(async () => {
|
||||
return await _channel.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
|
||||
});
|
||||
}
|
||||
this.connection.on("error", (err) => {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false))
|
||||
return;
|
||||
this.player.emit("connectionError", this, err);
|
||||
});
|
||||
this.connection.on("debug", (msg) => {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false))
|
||||
return;
|
||||
this.player.emit("debug", this, msg);
|
||||
});
|
||||
this.player.emit("connectionCreate", this, this.connection);
|
||||
this.connection.on("start", (resource) => {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false))
|
||||
return;
|
||||
this.playing = true;
|
||||
if (!this._filtersUpdate)
|
||||
this.player.emit("trackStart", this, resource?.metadata ?? this.current);
|
||||
this._filtersUpdate = false;
|
||||
});
|
||||
this.connection.on("finish", async (resource) => {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false))
|
||||
return;
|
||||
this.playing = false;
|
||||
if (this._filtersUpdate)
|
||||
return;
|
||||
this._streamTime = 0;
|
||||
if (resource?.metadata)
|
||||
this.previousTracks.push(resource.metadata);
|
||||
this.player.emit("trackEnd", this, resource.metadata);
|
||||
if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.OFF) {
|
||||
if (this.options.leaveOnEnd)
|
||||
this.destroy();
|
||||
this.player.emit("queueEnd", this);
|
||||
}
|
||||
else if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.AUTOPLAY) {
|
||||
this._handleAutoplay(Util_1.Util.last(this.previousTracks));
|
||||
}
|
||||
else {
|
||||
if (this.repeatMode === types_1.QueueRepeatMode.TRACK)
|
||||
return void this.play(Util_1.Util.last(this.previousTracks), { immediate: true });
|
||||
if (this.repeatMode === types_1.QueueRepeatMode.QUEUE)
|
||||
this.tracks.push(Util_1.Util.last(this.previousTracks));
|
||||
const nextTrack = this.tracks.shift();
|
||||
this.play(nextTrack, { immediate: true });
|
||||
return;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Destroys this queue
|
||||
* @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy
|
||||
* @returns {void}
|
||||
*/
|
||||
destroy(disconnect = this.options.leaveOnStop) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (this.connection)
|
||||
this.connection.end();
|
||||
if (disconnect)
|
||||
this.connection?.disconnect();
|
||||
this.player.queues.delete(this.guild.id);
|
||||
this.player.voiceUtils.cache.delete(this.guild.id);
|
||||
tslib_1.__classPrivateFieldSet(this, _Queue_destroyed, true, "f");
|
||||
}
|
||||
/**
|
||||
* Skips current track
|
||||
* @returns {boolean}
|
||||
*/
|
||||
skip() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection)
|
||||
return false;
|
||||
this._filtersUpdate = false;
|
||||
this.connection.end();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Adds single track to the queue
|
||||
* @param {Track} track The track to add
|
||||
* @returns {void}
|
||||
*/
|
||||
addTrack(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!(track instanceof Track_1.default))
|
||||
throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK);
|
||||
this.tracks.push(track);
|
||||
this.player.emit("trackAdd", this, track);
|
||||
}
|
||||
/**
|
||||
* Adds multiple tracks to the queue
|
||||
* @param {Track[]} tracks Array of tracks to add
|
||||
*/
|
||||
addTracks(tracks) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!tracks.every((y) => y instanceof Track_1.default))
|
||||
throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK);
|
||||
this.tracks.push(...tracks);
|
||||
this.player.emit("tracksAdd", this, tracks);
|
||||
}
|
||||
/**
|
||||
* Sets paused state
|
||||
* @param {boolean} paused The paused state
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setPaused(paused) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection)
|
||||
return false;
|
||||
return paused ? this.connection.pause(true) : this.connection.resume();
|
||||
}
|
||||
/**
|
||||
* Sets bitrate
|
||||
* @param {number|auto} bitrate bitrate to set
|
||||
* @returns {void}
|
||||
*/
|
||||
setBitrate(bitrate) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection?.audioResource?.encoder)
|
||||
return;
|
||||
if (bitrate === "auto")
|
||||
bitrate = this.connection.channel?.bitrate ?? 64000;
|
||||
this.connection.audioResource.encoder.setBitrate(bitrate);
|
||||
}
|
||||
/**
|
||||
* Sets volume
|
||||
* @param {number} amount The volume amount
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setVolume(amount) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection)
|
||||
return false;
|
||||
tslib_1.__classPrivateFieldSet(this, _Queue_lastVolume, amount, "f");
|
||||
this.options.initialVolume = amount;
|
||||
return this.connection.setVolume(amount);
|
||||
}
|
||||
/**
|
||||
* Sets repeat mode
|
||||
* @param {QueueRepeatMode} mode The repeat mode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
setRepeatMode(mode) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (![types_1.QueueRepeatMode.OFF, types_1.QueueRepeatMode.QUEUE, types_1.QueueRepeatMode.TRACK, types_1.QueueRepeatMode.AUTOPLAY].includes(mode))
|
||||
throw new PlayerError_1.PlayerError(`Unknown repeat mode "${mode}"!`, PlayerError_1.ErrorStatusCode.UNKNOWN_REPEAT_MODE);
|
||||
if (mode === this.repeatMode)
|
||||
return false;
|
||||
this.repeatMode = mode;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* The current volume amount
|
||||
* @type {number}
|
||||
*/
|
||||
get volume() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection)
|
||||
return 100;
|
||||
return this.connection.volume;
|
||||
}
|
||||
set volume(amount) {
|
||||
this.setVolume(amount);
|
||||
}
|
||||
/**
|
||||
* The stream time of this queue
|
||||
* @type {number}
|
||||
*/
|
||||
get streamTime() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.connection)
|
||||
return 0;
|
||||
const playbackTime = this._streamTime + this.connection.streamTime;
|
||||
const NC = this._activeFilters.includes("nightcore") ? 1.25 : null;
|
||||
const VW = this._activeFilters.includes("vaporwave") ? 0.8 : null;
|
||||
if (NC && VW)
|
||||
return playbackTime * (NC + VW);
|
||||
return NC ? playbackTime * NC : VW ? playbackTime * VW : playbackTime;
|
||||
}
|
||||
set streamTime(time) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
this.seek(time);
|
||||
}
|
||||
/**
|
||||
* Returns enabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersEnabled() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return AudioFilters_1.default.names.filter((x) => this._activeFilters.includes(x));
|
||||
}
|
||||
/**
|
||||
* Returns disabled filters
|
||||
* @returns {AudioFilters}
|
||||
*/
|
||||
getFiltersDisabled() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return AudioFilters_1.default.names.filter((x) => !this._activeFilters.includes(x));
|
||||
}
|
||||
/**
|
||||
* Sets filters
|
||||
* @param {QueueFilters} filters Queue filters
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setFilters(filters) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!filters || !Object.keys(filters).length) {
|
||||
// reset filters
|
||||
const streamTime = this.streamTime;
|
||||
this._activeFilters = [];
|
||||
return await this.play(this.current, {
|
||||
immediate: true,
|
||||
filtersUpdate: true,
|
||||
seek: streamTime,
|
||||
encoderArgs: []
|
||||
});
|
||||
}
|
||||
const _filters = []; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
for (const filter in filters) {
|
||||
if (filters[filter] === true)
|
||||
_filters.push(filter);
|
||||
}
|
||||
if (this._activeFilters.join("") === _filters.join(""))
|
||||
return;
|
||||
const newFilters = AudioFilters_1.default.create(_filters).trim();
|
||||
const streamTime = this.streamTime;
|
||||
this._activeFilters = _filters;
|
||||
return await this.play(this.current, {
|
||||
immediate: true,
|
||||
filtersUpdate: true,
|
||||
seek: streamTime,
|
||||
encoderArgs: !_filters.length ? undefined : ["-af", newFilters]
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Seeks to the given time
|
||||
* @param {number} position The position
|
||||
* @returns {boolean}
|
||||
*/
|
||||
async seek(position) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.playing || !this.current)
|
||||
return false;
|
||||
if (position < 1)
|
||||
position = 0;
|
||||
if (position >= this.current.durationMS)
|
||||
return this.skip();
|
||||
await this.play(this.current, {
|
||||
immediate: true,
|
||||
filtersUpdate: true,
|
||||
seek: position
|
||||
});
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Plays previous track
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async back() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const prev = this.previousTracks[this.previousTracks.length - 2]; // because last item is the current track
|
||||
if (!prev)
|
||||
throw new PlayerError_1.PlayerError("Could not find previous track", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND);
|
||||
return await this.play(prev, { immediate: true });
|
||||
}
|
||||
/**
|
||||
* Clear this queue
|
||||
*/
|
||||
clear() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
this.tracks = [];
|
||||
this.previousTracks = [];
|
||||
}
|
||||
/**
|
||||
* Stops the player
|
||||
* @returns {void}
|
||||
*/
|
||||
stop() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return this.destroy();
|
||||
}
|
||||
/**
|
||||
* Shuffles this queue
|
||||
* @returns {boolean}
|
||||
*/
|
||||
shuffle() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.tracks.length || this.tracks.length < 2)
|
||||
return false;
|
||||
for (let i = this.tracks.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Removes a track from the queue
|
||||
* @param {Track|string|number} track The track to remove
|
||||
* @returns {Track}
|
||||
*/
|
||||
remove(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
let trackFound = null;
|
||||
if (typeof track === "number") {
|
||||
trackFound = this.tracks[track];
|
||||
if (trackFound) {
|
||||
this.tracks = this.tracks.filter((t) => t.id !== trackFound.id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
trackFound = this.tracks.find((s) => s.id === (track instanceof Track_1.default ? track.id : track));
|
||||
if (trackFound) {
|
||||
this.tracks = this.tracks.filter((s) => s.id !== trackFound.id);
|
||||
}
|
||||
}
|
||||
return trackFound;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the specified track. If found, returns the track index else returns -1.
|
||||
* @param {number|Track|string} track The track
|
||||
* @returns {number}
|
||||
*/
|
||||
getTrackPosition(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (typeof track === "number")
|
||||
return this.tracks[track] != null ? track : -1;
|
||||
return this.tracks.findIndex((pred) => pred.id === (track instanceof Track_1.default ? track.id : track));
|
||||
}
|
||||
/**
|
||||
* Jumps to particular track
|
||||
* @param {Track|number} track The track
|
||||
* @returns {void}
|
||||
*/
|
||||
jump(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const foundTrack = this.remove(track);
|
||||
if (!foundTrack)
|
||||
throw new PlayerError_1.PlayerError("Track not found", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND);
|
||||
this.tracks.splice(0, 0, foundTrack);
|
||||
return void this.skip();
|
||||
}
|
||||
/**
|
||||
* Jumps to particular track, removing other tracks on the way
|
||||
* @param {Track|number} track The track
|
||||
* @returns {void}
|
||||
*/
|
||||
skipTo(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const trackIndex = this.getTrackPosition(track);
|
||||
const removedTrack = this.remove(track);
|
||||
if (!removedTrack)
|
||||
throw new PlayerError_1.PlayerError("Track not found", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND);
|
||||
this.tracks.splice(0, trackIndex, removedTrack);
|
||||
return void this.skip();
|
||||
}
|
||||
/**
|
||||
* Inserts the given track to specified index
|
||||
* @param {Track} track The track to insert
|
||||
* @param {number} [index=0] The index where this track should be
|
||||
*/
|
||||
insert(track, index = 0) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!track || !(track instanceof Track_1.default))
|
||||
throw new PlayerError_1.PlayerError("track must be the instance of Track", PlayerError_1.ErrorStatusCode.INVALID_TRACK);
|
||||
if (typeof index !== "number" || index < 0 || !Number.isFinite(index))
|
||||
throw new PlayerError_1.PlayerError(`Invalid index "${index}"`, PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
|
||||
this.tracks.splice(index, 0, track);
|
||||
this.player.emit("trackAdd", this, track);
|
||||
}
|
||||
/**
|
||||
* @typedef {object} PlayerTimestamp
|
||||
* @property {string} current The current progress
|
||||
* @property {string} end The total time
|
||||
* @property {number} progress Progress in %
|
||||
*/
|
||||
/**
|
||||
* Returns player stream timestamp
|
||||
* @returns {PlayerTimestamp}
|
||||
*/
|
||||
getPlayerTimestamp() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const currentStreamTime = this.streamTime;
|
||||
const totalTime = this.current.durationMS;
|
||||
const currentTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(currentStreamTime));
|
||||
const endTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(totalTime));
|
||||
return {
|
||||
current: currentTimecode,
|
||||
end: endTimecode,
|
||||
progress: Math.round((currentStreamTime / totalTime) * 100)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Creates progress bar string
|
||||
* @param {PlayerProgressbarOptions} options The progress bar options
|
||||
* @returns {string}
|
||||
*/
|
||||
createProgressBar(options = { timecodes: true }) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
const length = typeof options.length === "number" ? (options.length <= 0 || options.length === Infinity ? 15 : options.length) : 15;
|
||||
const index = Math.round((this.streamTime / this.current.durationMS) * length);
|
||||
const indicator = typeof options.indicator === "string" && options.indicator.length > 0 ? options.indicator : "🔘";
|
||||
const line = typeof options.line === "string" && options.line.length > 0 ? options.line : "▬";
|
||||
if (index >= 1 && index <= length) {
|
||||
const bar = line.repeat(length - 1).split("");
|
||||
bar.splice(index, 0, indicator);
|
||||
if (options.timecodes) {
|
||||
const timestamp = this.getPlayerTimestamp();
|
||||
return `${timestamp.current} ┃ ${bar.join("")} ┃ ${timestamp.end}`;
|
||||
}
|
||||
else {
|
||||
return `${bar.join("")}`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (options.timecodes) {
|
||||
const timestamp = this.getPlayerTimestamp();
|
||||
return `${timestamp.current} ┃ ${indicator}${line.repeat(length - 1)} ┃ ${timestamp.end}`;
|
||||
}
|
||||
else {
|
||||
return `${indicator}${line.repeat(length - 1)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Total duration
|
||||
* @type {Number}
|
||||
*/
|
||||
get totalTime() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return this.tracks.length > 0 ? this.tracks.map((t) => t.durationMS).reduce((p, c) => p + c) : 0;
|
||||
}
|
||||
/**
|
||||
* Play stream in a voice/stage channel
|
||||
* @param {Track} [src] The track to play (if empty, uses first track from the queue)
|
||||
* @param {PlayOptions} [options] The options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async play(src, options = {}) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false))
|
||||
return;
|
||||
if (!this.connection || !this.connection.voiceConnection)
|
||||
throw new PlayerError_1.PlayerError("Voice connection is not available, use <Queue>.connect()!", PlayerError_1.ErrorStatusCode.NO_CONNECTION);
|
||||
if (src && (this.playing || this.tracks.length) && !options.immediate)
|
||||
return this.addTrack(src);
|
||||
const track = options.filtersUpdate && !options.immediate ? src || this.current : src ?? this.tracks.shift();
|
||||
if (!track)
|
||||
return;
|
||||
this.player.emit("debug", this, "Received play request");
|
||||
if (!options.filtersUpdate) {
|
||||
this.previousTracks = this.previousTracks.filter((x) => x.id !== track.id);
|
||||
this.previousTracks.push(track);
|
||||
}
|
||||
let stream = null;
|
||||
const hasCustomDownloader = typeof this.onBeforeCreateStream === "function";
|
||||
if (["youtube", "spotify"].includes(track.raw.source)) {
|
||||
let spotifyResolved = false;
|
||||
if (this.options.spotifyBridge && track.raw.source === "spotify" && !track.raw.engine) {
|
||||
track.raw.engine = await play_dl_1.default.search(`${track.author} ${track.title}`, { source: { youtube: "video" } })
|
||||
.then(res => res[0].url)
|
||||
.catch(() => null);
|
||||
spotifyResolved = true;
|
||||
}
|
||||
const url = track.raw.source === "spotify" ? track.raw.engine : track.url;
|
||||
if (!url)
|
||||
return void this.play(this.tracks.shift(), { immediate: true });
|
||||
if (hasCustomDownloader) {
|
||||
stream = (await this.onBeforeCreateStream(track, spotifyResolved ? "youtube" : track.raw.source, this)) || null;
|
||||
}
|
||||
if (!stream) {
|
||||
stream = (await play_dl_1.default.stream(url, { discordPlayerCompatibility: true })).stream;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const arbitraryStream = (hasCustomDownloader && (await this.onBeforeCreateStream(track, track.raw.source || track.raw.engine, this))) || null;
|
||||
stream =
|
||||
arbitraryStream || (track.raw.source === "soundcloud" && typeof track.raw.engine?.downloadProgressive === "function")
|
||||
? await track.raw.engine.downloadProgressive()
|
||||
: typeof track.raw.engine === "function"
|
||||
? await track.raw.engine()
|
||||
: track.raw.engine;
|
||||
}
|
||||
const ffmpegStream = (0, FFmpegStream_1.createFFmpegStream)(stream, {
|
||||
encoderArgs: options.encoderArgs || [],
|
||||
seek: options.seek ? options.seek / 1000 : 0,
|
||||
fmt: "s16le"
|
||||
}).on("error", (err) => {
|
||||
if (!`${err}`.toLowerCase().includes("premature close"))
|
||||
this.player.emit("error", this, err);
|
||||
});
|
||||
const resource = this.connection.createStream(ffmpegStream, {
|
||||
type: voice_1.StreamType.Raw,
|
||||
data: track,
|
||||
disableVolume: Boolean(this.options.disableVolume)
|
||||
});
|
||||
if (options.seek)
|
||||
this._streamTime = options.seek;
|
||||
this._filtersUpdate = options.filtersUpdate;
|
||||
const volumeTransformer = resource.volume;
|
||||
if (volumeTransformer && typeof this.options.initialVolume === "number")
|
||||
Reflect.set(volumeTransformer, "volume", Math.pow(this.options.initialVolume / 100, 1.660964));
|
||||
if (volumeTransformer?.hasSmoothness && typeof this.options.volumeSmoothness === "number") {
|
||||
if (typeof volumeTransformer.setSmoothness === "function")
|
||||
volumeTransformer.setSmoothness(this.options.volumeSmoothness || 0);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.connection.playStream(resource);
|
||||
}, tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_getBufferingTimeout).call(this)).unref();
|
||||
}
|
||||
/**
|
||||
* Private method to handle autoplay
|
||||
* @param {Track} track The source track to find its similar track for autoplay
|
||||
* @returns {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _handleAutoplay(track) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!track || ![track.source, track.raw?.source].includes("youtube")) {
|
||||
if (this.options.leaveOnEnd)
|
||||
this.destroy();
|
||||
return void this.player.emit("queueEnd", this);
|
||||
}
|
||||
const info = await play_dl_1.default.video_info(track.url)
|
||||
.catch(Util_1.Util.noop);
|
||||
if (!info) {
|
||||
if (this.options.leaveOnEnd)
|
||||
this.destroy();
|
||||
return void this.player.emit("queueEnd", this);
|
||||
}
|
||||
const randomRelated = await play_dl_1.default.video_info(info.related_videos[0]);
|
||||
const nextTrack = new Track_1.default(this.player, {
|
||||
title: randomRelated.video_details.title,
|
||||
url: randomRelated.video_details.url,
|
||||
duration: randomRelated.video_details.durationRaw ? Util_1.Util.buildTimeCode(Util_1.Util.parseMS(randomRelated.video_details.durationInSec * 1000)) : "0:00",
|
||||
description: "",
|
||||
thumbnail: Util_1.Util.last(randomRelated.video_details.thumbnails).url,
|
||||
views: randomRelated.video_details.views,
|
||||
author: randomRelated.video_details.channel.name,
|
||||
requestedBy: track.requestedBy,
|
||||
source: "youtube"
|
||||
});
|
||||
this.play(nextTrack, { immediate: true });
|
||||
}
|
||||
*[(_Queue_lastVolume = new WeakMap(), _Queue_destroyed = new WeakMap(), _Queue_instances = new WeakSet(), Symbol.iterator)]() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
yield* this.tracks;
|
||||
}
|
||||
/**
|
||||
* JSON representation of this queue
|
||||
* @returns {object}
|
||||
*/
|
||||
toJSON() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
return {
|
||||
id: this.id,
|
||||
guild: this.guild.id,
|
||||
voiceChannel: this.connection?.channel?.id,
|
||||
options: this.options,
|
||||
tracks: this.tracks.map((m) => m.toJSON())
|
||||
};
|
||||
}
|
||||
/**
|
||||
* String representation of this queue
|
||||
* @returns {string}
|
||||
*/
|
||||
toString() {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
|
||||
return;
|
||||
if (!this.tracks.length)
|
||||
return "No songs available to display!";
|
||||
return `**Upcoming Songs:**\n${this.tracks.map((m, i) => `${i + 1}. **${m.title}**`).join("\n")}`;
|
||||
}
|
||||
}
|
||||
exports.Queue = Queue;
|
||||
_Queue_watchDestroyed = function _Queue_watchDestroyed(emit = true) {
|
||||
if (tslib_1.__classPrivateFieldGet(this, _Queue_destroyed, "f")) {
|
||||
if (emit)
|
||||
this.player.emit("error", this, new PlayerError_1.PlayerError("Cannot use destroyed queue", PlayerError_1.ErrorStatusCode.DESTROYED_QUEUE));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, _Queue_getBufferingTimeout = function _Queue_getBufferingTimeout() {
|
||||
const timeout = this.options.bufferingTimeout;
|
||||
if (isNaN(timeout) || timeout < 0 || !Number.isFinite(timeout))
|
||||
return 1000;
|
||||
return timeout;
|
||||
};
|
53
helpers/Music/dist/Structures/Track.d.ts
vendored
53
helpers/Music/dist/Structures/Track.d.ts
vendored
|
@ -1,53 +0,0 @@
|
|||
import { User } from "discord.js";
|
||||
import { Player } from "../Player";
|
||||
import { RawTrackData, TrackJSON } from "../types/types";
|
||||
import { Playlist } from "./Playlist";
|
||||
import { Queue } from "./Queue";
|
||||
declare class Track {
|
||||
player: Player;
|
||||
title: string;
|
||||
description: string;
|
||||
author: string;
|
||||
url: string;
|
||||
thumbnail: string;
|
||||
duration: string;
|
||||
views: number;
|
||||
requestedBy: User;
|
||||
playlist?: Playlist;
|
||||
readonly raw: RawTrackData;
|
||||
readonly id: string;
|
||||
/**
|
||||
* Track constructor
|
||||
* @param {Player} player The player that instantiated this Track
|
||||
* @param {RawTrackData} data Track data
|
||||
*/
|
||||
constructor(player: Player, data: RawTrackData);
|
||||
private _patch;
|
||||
/**
|
||||
* The queue in which this track is located
|
||||
* @type {Queue}
|
||||
*/
|
||||
get queue(): Queue;
|
||||
/**
|
||||
* The track duration in millisecond
|
||||
* @type {number}
|
||||
*/
|
||||
get durationMS(): number;
|
||||
/**
|
||||
* Returns source of this track
|
||||
* @type {TrackSource}
|
||||
*/
|
||||
get source(): import("../types/types").TrackSource;
|
||||
/**
|
||||
* String representation of this track
|
||||
* @returns {string}
|
||||
*/
|
||||
toString(): string;
|
||||
/**
|
||||
* Raw JSON representation of this track
|
||||
* @returns {TrackJSON}
|
||||
*/
|
||||
toJSON(hidePlaylist?: boolean): TrackJSON;
|
||||
}
|
||||
export default Track;
|
||||
export { Track };
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue