From 4756b42622130696c9873afb394b3bb40cae6078 Mon Sep 17 00:00:00 2001 From: JonnyBro Date: Sat, 6 Aug 2022 20:47:47 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BA=D0=B0=D1=82=D0=B5=D0=B3=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=8F=20Moderation,=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE?= =?UTF-8?q?=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B8?= =?UTF-8?q?=D0=B3=D1=80=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BC=D1=83?= =?UTF-8?q?=D0=B7=D1=8B=D0=BA=D0=B8=20=D1=81=20YouTube=20Music?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TO REWRITE/Administration/stealemoji.js | 39 ----- TO REWRITE/Moderation/clear.js | 80 --------- TO REWRITE/Moderation/clearwarns.js | 35 ---- TO REWRITE/Moderation/giveaway.js | 127 --------------- TO REWRITE/Moderation/poll.js | 114 ------------- TO REWRITE/Moderation/unban.js | 60 ------- {commands/Music => TO REWRITE}/seek.js | 0 commands/Administration/stealemoji.js | 57 +++++++ commands/Fun/memes.js | 10 +- commands/General/activity.js | 10 +- commands/General/emoji.js | 4 + commands/General/report.js | 3 +- commands/General/suggest.js | 3 +- commands/Moderation/clear.js | 110 +++++++++++++ commands/Moderation/clearwarns.js | 52 ++++++ commands/Moderation/giveaway.js | 196 +++++++++++++++++++++++ commands/Moderation/poll.js | 127 +++++++++++++++ commands/Moderation/unban.js | 49 ++++++ commands/Moderation/warn.js | 10 +- commands/Moderation/warns.js | 2 +- commands/Music/clips.js | 26 +-- commands/NSFW/nsfw.js | 8 +- commands/Owner/debug.js | 2 +- helpers/extenders.js | 27 ++++ helpers/extractor.js | 31 +++- languages/ru-RU/common.json | 4 +- languages/ru-RU/general/emoji.json | 1 + languages/ru-RU/misc.json | 3 +- languages/ru-RU/moderation/clear.json | 7 +- languages/ru-RU/moderation/giveaway.json | 13 +- languages/ru-RU/moderation/poll.json | 7 +- languages/ru-RU/moderation/unban.json | 8 +- languages/ru-RU/music/play.json | 2 +- languages/ru-RU/owner/debug.json | 1 - 34 files changed, 716 insertions(+), 512 deletions(-) delete mode 100644 TO REWRITE/Administration/stealemoji.js delete mode 100644 TO REWRITE/Moderation/clear.js delete mode 100644 TO REWRITE/Moderation/clearwarns.js delete mode 100644 TO REWRITE/Moderation/giveaway.js delete mode 100644 TO REWRITE/Moderation/poll.js delete mode 100644 TO REWRITE/Moderation/unban.js rename {commands/Music => TO REWRITE}/seek.js (100%) create mode 100644 commands/Administration/stealemoji.js create mode 100644 commands/Moderation/clear.js create mode 100644 commands/Moderation/clearwarns.js create mode 100644 commands/Moderation/giveaway.js create mode 100644 commands/Moderation/poll.js create mode 100644 commands/Moderation/unban.js diff --git a/TO REWRITE/Administration/stealemoji.js b/TO REWRITE/Administration/stealemoji.js deleted file mode 100644 index bef0eff4..00000000 --- a/TO REWRITE/Administration/stealemoji.js +++ /dev/null @@ -1,39 +0,0 @@ -const Command = require("../../base/Command"), - { parseEmoji } = require("discord.js"); - -class Stealemoji extends Command { - constructor(client) { - super(client, { - name: "stealemoji", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["steale"], - memberPermissions: ["MANAGE_GUILD"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args) { - if (!args.length) return message.error("administration/stealemoji:MISSING_EMOJI"); - - for (const rawEmoji of args) { - const parsedEmoji = parseEmoji(rawEmoji); - const extension = parsedEmoji.animated ? "gif" : "png"; - - message.guild.emojis - .create(`https://cdn.discordapp.com/emojis/${parsedEmoji.id}.${extension}`, parsedEmoji.name) - .then(emoji => message.success("administration/stealemoji:SUCCESS", { - emoji: emoji.name - })) - .catch(() => message.error("administration/stealemoji:ERROR", { - emoji: parsedEmoji.name - })); - } - } -} - -module.exports = Stealemoji; \ No newline at end of file diff --git a/TO REWRITE/Moderation/clear.js b/TO REWRITE/Moderation/clear.js deleted file mode 100644 index e4b1c27d..00000000 --- a/TO REWRITE/Moderation/clear.js +++ /dev/null @@ -1,80 +0,0 @@ -const Command = require("../../base/Command"); - -class Clear extends Command { - constructor(client) { - super(client, { - name: "clear", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["cl", "purge"], - memberPermissions: ["MANAGE_MESSAGES"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS", "MANAGE_MESSAGES"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args) { - if (args[0] === "all") { - message.channel.send(message.translate("moderation/clear:ALL_CONFIRM")); - - const filter = m => m.author.id === message.author.id && m.content === "confirm"; - const collector = message.channel.createMessageCollector({ - filter, - time: 120000 // 2 minutes - }); - - collector.on("collect", async message => { - const position = message.channel.position; - const newChannel = await message.channel.clone(); - await message.channel.delete(); - newChannel.setPosition(position); - return newChannel.send({ - content: message.translate("moderation/clear:CHANNEL_CLEARED") - }); - }); - - collector.on("end", (_, reason) => { - if (reason === "time") return message.error("misc:TIMES_UP"); - }); - } else { - const amount = args[0]; - if (!amount || isNaN(amount) || parseInt(amount) < 1) return message.error("moderation/clear:MISSING_AMOUNT"); - - await message.delete(); - - const user = message.mentions.users.first(); - - let messages = await message.channel.messages.fetch({ - limit: amount - }); - if (user) messages = messages.filter((m) => m.author.id === user.id); - if (messages.length > amount) messages.length = parseInt(amount, 10); - - messages = messages.filter((m) => !m.pinned); - - message.channel.bulkDelete(messages, true); - - let toDelete = null; - - if (user) { - toDelete = await message.channel.send(message.translate("moderation/clear:CLEARED_MEMBER", { - amount: `${amount} ${message.getNoun(amount, message.translate("misc:NOUNS:MESSAGES:1"), message.translate("misc:NOUNS:MESSAGES:2"), message.translate("misc:NOUNS:MESSAGES:5"))}`, - username: user.tag - })); - } else { - toDelete = await message.channel.send(message.translate("moderation/clear:CLEARED", { - amount: `${amount} ${message.getNoun(amount, message.translate("misc:NOUNS:MESSAGES:1"), message.translate("misc:NOUNS:MESSAGES:2"), message.translate("misc:NOUNS:MESSAGES:5"))}` - })); - } - - setTimeout(function () { - toDelete.delete(); - }, 2000); - } - } -} - -module.exports = Clear; \ No newline at end of file diff --git a/TO REWRITE/Moderation/clearwarns.js b/TO REWRITE/Moderation/clearwarns.js deleted file mode 100644 index 5303012f..00000000 --- a/TO REWRITE/Moderation/clearwarns.js +++ /dev/null @@ -1,35 +0,0 @@ -const Command = require("../../base/Command"); - -class Clearwarns extends Command { - constructor(client) { - super(client, { - name: "clearwarns", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["clearw", "clw"], - memberPermissions: ["MANAGE_MESSAGES"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args) { - const member = await this.client.resolveMember(args[0], message.guild); - if (!member) return message.error("moderation/clearwarns:MISSING_MEMBER"); - - const memberData = await this.client.findOrCreateMember({ - id: member.id, - guildID: message.guild.id - }); - memberData.sanctions = []; - memberData.save(); - message.success("moderation/clearwarns:SUCCESS", { - username: member.user.tag - }); - } -} - -module.exports = Clearwarns; \ No newline at end of file diff --git a/TO REWRITE/Moderation/giveaway.js b/TO REWRITE/Moderation/giveaway.js deleted file mode 100644 index e90878f7..00000000 --- a/TO REWRITE/Moderation/giveaway.js +++ /dev/null @@ -1,127 +0,0 @@ -const Command = require("../../base/Command"), - ms = require("ms"); - -class Giveaway extends Command { - constructor(client) { - super(client, { - name: "giveaway", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["gaway"], - memberPermissions: ["MENTION_EVERYONE"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 2000 - }); - } - - async run(message, args, data) { - const status = args[0]; - if (!status) return message.error("moderation/giveaway:MISSING_STATUS"); - - if (status === "create") { - const currentGiveaways = this.client.giveawaysManager.giveaways.filter((g) => g.guildId === message.guild.id && !g.ended).length; - if (currentGiveaways > 3) return message.error("moderation/giveaway:MAX_COUNT"); - - const time = args[1]; - if (!time) return message.error("moderation/giveaway:INVALID_CREATE", { prefix: data.guild.prefix }); - if (isNaN(ms(time))) return message.error("misc:INVALID_TIME"); - if (ms(time) > ms("15d")) return message.error("moderation/giveaway:MAX_DURATION"); - - const winnersCount = args[2]; - if (!winnersCount) return message.error("moderation/giveaway:INVALID_CREATE", { prefix: data.guild.prefix }); - if (isNaN(winnersCount) || winnersCount > 10 || winnersCount < 1) return message.error("misc:INVALID_NUMBER_RANGE", { min: 1, max: 10 }); - - const drop = (args[3] === "true"); - let prize = args.slice(3).join(" "); - - if (drop) prize = args.slice(4).join(" "); - else prize = args.slice(3).join(" "); - - if (!prize) return message.error("moderation/giveaway:INVALID_CREATE", { prefix: data.guild.prefix }); - - this.client.giveawaysManager.start(message.channel, { - duration: ms(time), - winnerCount: parseInt(winnersCount, 10), - prize: prize, - hostedBy: message.author, - isDrop: drop, - messages: { - giveaway: message.translate("moderation/giveaway:TITLE"), - giveawayEnded: message.translate("moderation/giveaway:ENDED"), - timeRemaining: message.translate("moderation/giveaway:TIME_REMAINING"), - inviteToParticipate: message.translate("moderation/giveaway:INVITE_PARTICIPATE"), - winMessage: message.translate("moderation/giveaway:WIN_MESSAGE"), - drawing: message.translate("moderation/giveaway:DRAWING"), - dropMessage: message.translate("moderation/giveaway:DROP"), - embedFooter: message.translate("moderation/giveaway:FOOTER"), - noWinner: message.translate("moderation/giveaway:NO_WINNER"), - winners: message.translate("moderation/giveaway:WINNERS"), - endedAt: message.translate("moderation/giveaway:END_AT"), - hostedBy: message.translate("moderation/giveaway:HOSTEDBY"), - units: { - seconds: message.translate("time:SECONDS", { - amount: "" - }).trim(), - minutes: message.translate("time:MINUTES", { - amount: "" - }).trim(), - hours: message.translate("time:HOURS", { - amount: "" - }).trim(), - days: message.translate("time:DAYS", { - amount: "" - }).trim() - } - } - }).then(() => { - message.success("moderation/giveaway:GIVEAWAY_CREATED"); - }); - } else if (status === "reroll") { - const messageID = args[1]; - if (!messageID) return message.error("moderation/giveaway:MISSING_ID"); - - this.client.giveawaysManager.reroll(messageID, { - messages: { - congrat: message.translate("moderation/giveaway:REROLL_CONGRAT"), - error: message.translate("moderation/giveaway:REROLL_ERROR") - } - }).then(() => { - return message.success("moderation/giveaway:GIVEAWAY_REROLLED"); - }).catch(() => { - return message.error("moderation/giveaway:NOT_FOUND_ENDED", { - messageID - }); - }); - } else if (status === "delete") { - const messageID = args[1]; - if (!messageID) return message.error("moderation/giveaway:MISSING_ID"); - - this.client.giveawaysManager.delete(messageID).then(() => { - return message.success("moderation/giveaway:GIVEAWAY_DELETED"); - }).catch(() => { - return message.error("moderation/giveaway:NOT_FOUND", { - messageID - }); - }); - } else if (status === "end") { - const messageID = args[1]; - if (!messageID) return message.error("moderation/giveaway:MISSING_ID"); - - try { - this.client.giveawaysManager.end(messageID); - return message.success("moderation/giveaway:GIVEAWAY_ENDED"); - } catch (e) { - return message.error("moderation/giveaway:NOT_FOUND", { - messageID - }); - } - } else { - return message.error("moderation/giveaway:MISSING_STATUS"); - } - } -} - -module.exports = Giveaway; \ No newline at end of file diff --git a/TO REWRITE/Moderation/poll.js b/TO REWRITE/Moderation/poll.js deleted file mode 100644 index 8b59985b..00000000 --- a/TO REWRITE/Moderation/poll.js +++ /dev/null @@ -1,114 +0,0 @@ -const Command = require("../../base/Command"), - Discord = require("discord.js"); - -class Poll extends Command { - constructor(client) { - super(client, { - name: "poll", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["po"], - memberPermissions: ["MANAGE_MESSAGES"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args, data) { - const question = args.join(" "); - if (!question) return message.error("moderation/poll:MISSING_QUESTION"); - - let mention = null; - const msg = await message.sendT("moderation/announcement:MENTION_PROMPT"); - - const filter = m => m.author.id === message.author.id; - const collector = new Discord.MessageCollector(message.channel, { - filter, - time: 240000 - }); - - collector.on("collect", async tmsg => { - if (tmsg.content.toLowerCase() === message.translate("common:NO").toLowerCase()) { - tmsg.delete(); - msg.delete(); - collector.stop(true); - - message.delete(); - } - - if (tmsg.content.toLowerCase() === message.translate("common:YES").toLowerCase()) { - tmsg.delete(); - msg.delete(); - const tmsg1 = await message.channel.send(message.translate("moderation/announcement:MENTION_TYPE_PROMPT")); - - const filter = m => m.author.id === message.author.id; - const c = new Discord.MessageCollector(message.channel, { - filter, - time: 60000 - }); - - c.on("collect", (m) => { - if (m.content.toLowerCase() === "here") { - mention = "@here"; - tmsg1.delete(); - m.delete(); - collector.stop(true); - c.stop(true); - } else if (m.content.toLowerCase() === "everyone") { - mention = "@everyone"; - tmsg1.delete(); - m.delete(); - collector.stop(true); - c.stop(true); - } - }); - - c.on("end", (collected, reason) => { - if (reason === "time") return message.error("misc:TIMES_UP"); - }); - - message.delete(); - } - }); - - collector.on("end", (collected, reason) => { - if (reason === "time") return message.error("misc:TIMES_UP"); - - const success = this.client.customEmojis.success.split(":")[1]; - const error = this.client.customEmojis.error.split(":")[1]; - - const emojis = [ - this.client.emojis.cache.find(e => e.name === success), - this.client.emojis.cache.find(e => e.name === error) - ]; - - const embed = new Discord.EmbedBuilder() - .setAuthor({ - name: message.translate("moderation/poll:TITLE") - }) - .setColor(data.config.embed.color) - .addFields([ - { - name: question, - value: message.translate("moderation/poll:REACT", { - success: emojis[0].toString(), - error: emojis[1].toString() - }) - } - ]); - - message.channel.send({ - content: mention, - embeds: [embed] - }).then(async (m) => { - await m.react(emojis[0]); - await m.react(emojis[1]); - }); - }); - } -} - -module.exports = Poll; \ No newline at end of file diff --git a/TO REWRITE/Moderation/unban.js b/TO REWRITE/Moderation/unban.js deleted file mode 100644 index ea0468be..00000000 --- a/TO REWRITE/Moderation/unban.js +++ /dev/null @@ -1,60 +0,0 @@ -const Command = require("../../base/Command"); - -class Unban extends Command { - constructor(client) { - super(client, { - name: "unban", - dirname: __dirname, - enabled: true, - guildOnly: true, - aliases: ["ub"], - memberPermissions: ["BAN_MEMBERS"], - botPermissions: ["SEND_MESSAGES", "EMBED_LINKS", "BAN_MEMBERS"], - nsfw: false, - ownerOnly: false, - cooldown: 1000 - }); - } - - async run(message, args) { - let user = null; - - if (!args[0]) return message.error("moderation/unban:MISSING_ID"); - - // Check if the arg is an ID or a username - const isId = !isNaN(args[0]); - - if (isId) { - // Try to find a user with that ID - await this.client.users.fetch(args[0]).then((u) => { - // if a user was found - user = u; - }).catch(() => {}); - } else if (!isId) { - const arr = args[0].split("#"); - if (arr.length < 2) { - return message.error("misc:NO_USER_FOUND_ID", { - id: args[0] - }); - } - user = this.client.users.filter((u) => u.username === arr[0]).find((u) => u.discriminator === arr[1]); - } - - if (!user) return message.error("misc:NO_USER_FOUND_ID", { id: args[0] }); - - // check if the user is banned - const banned = await message.guild.bans.fetch(); - if (!banned.some((e) => e.user.id === user.id)) return message.success("moderation/unban:NOT_BANNED", { username: user.tag }); - - // Unban user - message.guild.members.unban(user).catch(() => {}); - - // Send a success message in the current channel - message.success("moderation/unban:UNBANNED", { - username: user.tag, - server: message.guild.name - }); - } -} - -module.exports = Unban; \ No newline at end of file diff --git a/commands/Music/seek.js b/TO REWRITE/seek.js similarity index 100% rename from commands/Music/seek.js rename to TO REWRITE/seek.js diff --git a/commands/Administration/stealemoji.js b/commands/Administration/stealemoji.js new file mode 100644 index 00000000..08b96239 --- /dev/null +++ b/commands/Administration/stealemoji.js @@ -0,0 +1,57 @@ +const { SlashCommandBuilder, parseEmoji, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Stealemoji extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("stealemoji") + .setDescription(client.translate("administration/stealemoji:DESCRIPTION")) + .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) + .addStringOption(option => option.setName("emoji") + .setDescription(client.translate("common:EMOJI")) + .setRequired(true)), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const parsedEmoji = parseEmoji(interaction.options.getString("emoji")); + const ext = parsedEmoji.animated ? "gif" : "png"; + + interaction.guild.emojis + .create({ + name: parsedEmoji.name, + attachment: `https://cdn.discordapp.com/emojis/${parsedEmoji.id}.${ext}` + }) + .then(emoji => interaction.success("administration/stealemoji:SUCCESS", { + emoji: emoji.name + }, { ephemeral: true })) + .catch(e => { + console.log(e); + interaction.error("administration/stealemoji:ERROR", { + emoji: parsedEmoji.name + }, { ephemeral: true }); + }); + } +} + +module.exports = Stealemoji; \ No newline at end of file diff --git a/commands/Fun/memes.js b/commands/Fun/memes.js index 621ff3d6..35e0e3a5 100644 --- a/commands/Fun/memes.js +++ b/commands/Fun/memes.js @@ -53,14 +53,16 @@ class Memes extends BaseCommand { fetchReply: true }); + const filter = i => i.customId === "memes_select" && i.user.id === interaction.user.id; const collector = new InteractionCollector(client, { + filter, componentType: ComponentType.SelectMenu, message: msg, - idle: 60 * 1000 + idle: 30 * 1000 }); - collector.on("collect", async msg => { - const tag = msg?.values[0]; + collector.on("collect", async i => { + const tag = i?.values[0]; const res = await fetch(`https://meme-api.herokuapp.com/gimme/${tag}`).then(response => response.json()); const embed = new EmbedBuilder() @@ -72,7 +74,7 @@ class Memes extends BaseCommand { .setImage(res.url) .setTimestamp(); - await msg.update({ + await i.update({ embeds: [embed] }); }); diff --git a/commands/General/activity.js b/commands/General/activity.js index 4576f9df..49c5a865 100644 --- a/commands/General/activity.js +++ b/commands/General/activity.js @@ -59,14 +59,16 @@ class Activity extends BaseCommand { fetchReply: true }); + const filter = i => i.customId === "activity_select" && i.user.id === interaction.user.id; const collector = new InteractionCollector(client, { + filter, componentType: ComponentType.SelectMenu, message: msg, - idle: 60 * 1000 + idle: 30 * 1000 }); - collector.on("collect", async msg => { - const activity = msg?.values[0]; + collector.on("collect", async i => { + const activity = i?.values[0]; const invite = await client.discordTogether.createTogetherCode(voice.id, activity); const embed = new EmbedBuilder() @@ -78,7 +80,7 @@ class Activity extends BaseCommand { }) .setTimestamp(); - await msg.update({ + await i.update({ embeds: [embed], components: [] }); diff --git a/commands/General/emoji.js b/commands/General/emoji.js index 28c6a98b..0743f068 100644 --- a/commands/General/emoji.js +++ b/commands/General/emoji.js @@ -59,6 +59,10 @@ class Emoji extends BaseCommand { { name: interaction.translate("general/emoji:ID"), value: parsedEmoji.id?.toString() || interaction.translate("general/emoji:STANDART") + }, + { + name: interaction.translate("general/emoji:LINK"), + value: `https://cdn.discordapp.com/emojis/${parsedEmoji.id}.${parsedEmoji.animated ? "gif" : "png"}` } ]); diff --git a/commands/General/report.js b/commands/General/report.js index de679288..fb5d81f2 100644 --- a/commands/General/report.js +++ b/commands/General/report.js @@ -37,7 +37,6 @@ class Report extends BaseCommand { * @param {Array} data */ async execute(client, interaction) { - if (interaction.user.id === "285109105717280768") return interaction.reply({ content: "Пошёл нахуй фахон" }); const repChannel = interaction.guild.channels.cache.get(interaction.guild.data.plugins.reports); if (!repChannel) return interaction.error("general/report:MISSING_CHANNEL"); const member = interaction.options.getMember("user"); @@ -85,7 +84,7 @@ class Report extends BaseCommand { repChannel.send({ embeds: [embed] - }).then(async (m) => { + }).then(async m => { await m.react(success); await m.react(error); }); diff --git a/commands/General/suggest.js b/commands/General/suggest.js index a086af12..88593755 100644 --- a/commands/General/suggest.js +++ b/commands/General/suggest.js @@ -34,7 +34,6 @@ class Suggest extends BaseCommand { * @param {Array} data */ async execute(client, interaction) { - if (interaction.user.id === "285109105717280768") return interaction.reply({ content: "Пошёл нахуй фахон" }); const suggChannel = interaction.guild.channels.cache.get(interaction.guild.data.plugins.suggestions); if (!suggChannel) return interaction.error("general/suggest:MISSING_CHANNEL"); const suggestion = interaction.options.getString("message"); @@ -74,7 +73,7 @@ class Suggest extends BaseCommand { suggChannel.send({ embeds: [embed] - }).then(async (m) => { + }).then(async m => { await m.react(success); await m.react(error); }); diff --git a/commands/Moderation/clear.js b/commands/Moderation/clear.js new file mode 100644 index 00000000..f7057833 --- /dev/null +++ b/commands/Moderation/clear.js @@ -0,0 +1,110 @@ +const { SlashCommandBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Clear extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("clear") + .setDescription(client.translate("moderation/clear:DESCRIPTION")) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages) + .addStringOption(option => option.setName("option") + .setDescription(client.translate("moderation/clear:OPTION")) + .setRequired(true)) + .addUserOption(option => option.setName("user") + .setDescription(client.translate("common:USER"))), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const option = interaction.options.getString("option"); + const member = interaction.options.getMember("user"); + + if (option === "all") { + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId("clear_confirm_yes") + .setLabel(interaction.translate("common:ACCEPT")) + .setStyle(ButtonStyle.Danger), + new ButtonBuilder() + .setCustomId("clear_confirm_no") + .setLabel(interaction.translate("common:CANCEL")) + .setStyle(ButtonStyle.Secondary), + ); + + + await interaction.reply({ + content: interaction.translate("moderation/clear:ALL_CONFIRM"), + ephemeral: true, + components: [row] + }); + + const filter = i => i.user.id === interaction.user.id; + const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 }); + + collector.on("collect", async i => { + if (i.isButton()) { + if (i.customId === "clear_confirm_yes") { + const position = interaction.channel.position; + const newChannel = await interaction.channel.clone(); + await interaction.channel.delete(); + newChannel.setPosition(position); + + await newChannel.send({ + content: interaction.translate("moderation/clear:CHANNEL_CLEARED") + }); + } else if (i.customId === "clear_confirm_no") { + row.components[0].setDisabled(true); + row.components[1].setDisabled(true); + + i.update({ + content: interaction.translate("misc:SELECT_CANCELED") + }); + } + } + }); + } else { + if (isNaN(option) || parseInt(option) < 1) return interaction.error("moderation/clear:OPTION_NAN", null, { ephemeral: true }); + let messages = await interaction.channel.messages.fetch({ + limit: option + }); + if (member) messages = messages.filter(m => m.author.id === member.id); + if (messages.length > option) messages.length = parseInt(option, 10); + + interaction.channel.bulkDelete(messages.filter(m => !m.pinned), true); + + if (member) { + interaction.replyT("moderation/clear:CLEARED_MEMBER", { + amount: `${option} ${client.getNoun(option, interaction.translate("misc:NOUNS:MESSAGES:1"), interaction.translate("misc:NOUNS:MESSAGES:2"), interaction.translate("misc:NOUNS:MESSAGES:5"))}`, + username: member.user.tag + }, { ephemeral: true }); + } else { + interaction.replyT("moderation/clear:CLEARED", { + amount: `${option} ${client.getNoun(option, interaction.translate("misc:NOUNS:MESSAGES:1"), interaction.translate("misc:NOUNS:MESSAGES:2"), interaction.translate("misc:NOUNS:MESSAGES:5"))}` + }, { ephemeral: true }); + } + } + } +} + +module.exports = Clear; \ No newline at end of file diff --git a/commands/Moderation/clearwarns.js b/commands/Moderation/clearwarns.js new file mode 100644 index 00000000..358d3d42 --- /dev/null +++ b/commands/Moderation/clearwarns.js @@ -0,0 +1,52 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Clearwarns extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("clearwarns") + .setDescription(client.translate("moderation/clearwarns:DESCRIPTION")) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages) + .addUserOption(option => option.setName("user") + .setDescription(client.translate("common:USER")) + .setRequired(true)), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const member = interaction.options.getMember("user"); + + const memberData = await client.findOrCreateMember({ + id: member.id, + guildID: interaction.guildId + }); + + memberData.sanctions = []; + memberData.save(); + interaction.success("moderation/clearwarns:SUCCESS", { + username: member.user.tag + }); + } +} + +module.exports = Clearwarns; \ No newline at end of file diff --git a/commands/Moderation/giveaway.js b/commands/Moderation/giveaway.js new file mode 100644 index 00000000..8f0339db --- /dev/null +++ b/commands/Moderation/giveaway.js @@ -0,0 +1,196 @@ +const { SlashCommandBuilder, ActionRowBuilder, SelectMenuBuilder, InteractionCollector, ComponentType, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"), + ms = require("ms"); + +class Giveaway extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("giveaway") + .setDescription(client.translate("moderation/giveaway:DESCRIPTION")) + .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"))), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const options = ["create", "reroll", "delete", "end"].map(tag => + JSON.parse(JSON.stringify({ + label: tag, + value: tag + })) + ); + + const row = new ActionRowBuilder() + .addComponents( + new SelectMenuBuilder() + .setCustomId("giveaway_select") + .setPlaceholder(client.translate("common:NOTHING_SELECTED")) + .addOptions(options) + ); + + const msg = await interaction.reply({ + content: interaction.translate("common:AVAILABLE_CATEGORIES"), + components: [row], + ephemeral: true, + fetchReply: true + }); + + 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 + }); + + collector.on("collect", async i => { + const option = i?.values[0]; + + 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: [] + }); + } + } + }); + } +} + +module.exports = Giveaway; \ No newline at end of file diff --git a/commands/Moderation/poll.js b/commands/Moderation/poll.js new file mode 100644 index 00000000..085a460f --- /dev/null +++ b/commands/Moderation/poll.js @@ -0,0 +1,127 @@ +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Poll extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("poll") + .setDescription(client.translate("moderation/poll:DESCRIPTION")) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages) + .addStringOption(option => option.setName("question") + .setDescription(client.translate("moderation/poll:QUESTION")) + .setRequired(true)), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const question = interaction.options.getString("question"); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId("poll_everyone") + .setLabel(interaction.translate("moderation/poll:EVERYONE")) + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId("poll_here") + .setLabel(interaction.translate("moderation/poll:HERE")) + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId("poll_nothing") + .setLabel(interaction.translate("moderation/poll:NOTHING")) + .setStyle(ButtonStyle.Primary), + new ButtonBuilder() + .setCustomId("poll_cancel") + .setLabel(interaction.translate("common:CANCEL")) + .setStyle(ButtonStyle.Danger), + ); + + + await interaction.reply({ + content: interaction.translate("moderation/poll:SELECT_MENTION"), + ephemeral: true, + components: [row] + }); + + let mention = null; + const filter = i => i.user.id === interaction.user.id; + const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 }); + + collector.on("collect", async i => { + if (i.isButton()) { + if (i.customId === "poll_everyone") { + mention = "@everyone"; + i.update({ + content: interaction.translate("moderation/poll:POLL_SENDED"), + components: [] + }); + } else if (i.customId === "poll_here") { + mention = "@here"; + i.update({ + content: interaction.translate("moderation/poll:POLL_SENDED"), + components: [] + }); + } else if (i.customId === "poll_nothing") { + mention = null; + i.update({ + content: interaction.translate("moderation/poll:POLL_SENDED"), + components: [] + }); + } else if (i.customId === "poll_cancel") { + return i.update({ + content: interaction.translate("misc:SELECT_CANCELED"), + components: [] + }); + } + + const cool = client.emojis.cache.find(e => e.name === client.customEmojis.cool.split(":")[1]); + const notcool = client.emojis.cache.find(e => e.name === client.customEmojis.notcool.split(":")[1]); + + const embed = new EmbedBuilder() + .setAuthor({ + name: interaction.translate("moderation/poll:TITLE") + }) + .setColor(client.config.embed.color) + .addFields([ + { + name: question, + value: interaction.translate("moderation/poll:REACT", { + success: cool.toString(), + error: notcool.toString() + }) + } + ]); + + return interaction.channel.send({ + content: mention, + embeds: [embed] + }).then(async m => { + await m.react(cool); + await m.react(notcool); + }); + } + }); + } +} + +module.exports = Poll; \ No newline at end of file diff --git a/commands/Moderation/unban.js b/commands/Moderation/unban.js new file mode 100644 index 00000000..9f640c96 --- /dev/null +++ b/commands/Moderation/unban.js @@ -0,0 +1,49 @@ +const { SlashCommandBuilder, PermissionFlagsBits } = require("discord.js"); +const BaseCommand = require("../../base/BaseCommand"); + +class Unban extends BaseCommand { + /** + * + * @param {import("../../base/JaBa")} client + */ + constructor(client) { + super({ + command: new SlashCommandBuilder() + .setName("unban") + .setDescription(client.translate("moderation/unban:DESCRIPTION")) + .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers && PermissionFlagsBits.ManageMessages) + .addStringOption(option => option.setName("user_id") + .setDescription(client.translate("moderation/unban:ID")) + .setRequired(true)), + aliases: [], + dirname: __dirname, + guildOnly: true + }); + } + /** + * + * @param {import("../../base/JaBa")} client + */ + async onLoad() { + //... + } + /** + * + * @param {import("../../base/JaBa")} client + * @param {import("discord.js").ChatInputCommandInteraction} interaction + * @param {Array} data + */ + async execute(client, interaction) { + const id = interaction.options.getString("user_id"); + const banned = await interaction.guild.bans.fetch(); + if (!banned.find(u => u.user.id === id)) return interaction.error("moderation/unban:NOT_BANNED", { id }); + + interaction.guild.bans.remove(id); + + interaction.success("moderation/unban:UNBANNED", { + id + }); + } +} + +module.exports = Unban; \ No newline at end of file diff --git a/commands/Moderation/warn.js b/commands/Moderation/warn.js index e07d7cb9..6db6a35c 100644 --- a/commands/Moderation/warn.js +++ b/commands/Moderation/warn.js @@ -48,13 +48,11 @@ class Warn extends BaseCommand { .setTitle(interaction.translate("moderation/warn:MODAL_TITLE")); const reasonInput = new TextInputBuilder() - .setCustomId("reason") + .setCustomId("warn_reason") .setLabel(interaction.translate("moderation/warn:REASON")) .setStyle(TextInputStyle.Short); - const firstActionRow = new ActionRowBuilder().addComponents(reasonInput); - - modal.addComponents(firstActionRow); + modal.addComponents(new ActionRowBuilder().addComponents(reasonInput)); await interaction.showModal(modal); @@ -63,8 +61,8 @@ class Warn extends BaseCommand { filter: i => i.user.id === interaction.member.id, }); - if (submitted) { - const reason = submitted.fields.getTextInputValue("reason"); + if (submitted && submitted.customId === "warn_modal") { + const reason = submitted.fields.getTextInputValue("warn_reason"); const sanctions = memberData.sanctions.filter((s) => s.type === "warn").length; const banCount = data.guildData.plugins.warnsSanctions.ban; diff --git a/commands/Moderation/warns.js b/commands/Moderation/warns.js index 20a68a00..7e0425c0 100644 --- a/commands/Moderation/warns.js +++ b/commands/Moderation/warns.js @@ -30,7 +30,7 @@ class Warns extends BaseCommand { /** * * @param {import("../../base/JaBa")} client - * @param {import("discord.js").UserContextMenuCommandInteraction} interaction + * @param {import("discord.js").ChatInputCommandInteraction} interaction * @param {Array} data */ async execute(client, interaction) { diff --git a/commands/Music/clips.js b/commands/Music/clips.js index 13a74431..98072106 100644 --- a/commands/Music/clips.js +++ b/commands/Music/clips.js @@ -58,26 +58,28 @@ class Clips extends BaseCommand { fetchReply: true }); + const filter = i => i.customId === "clips_select" && i.user.id === interaction.user.id; const collector = new InteractionCollector(client, { + filter, componentType: ComponentType.SelectMenu, message: msg, - idle: 60 * 1000 + idle: 30 * 1000 }); - collector.on("collect", async msg => { - const clip = msg?.values[0]; - const voice = msg.member.voice.channel; - if (!voice) return msg.update({ content: interaction.translate("music/play:NO_VOICE_CHANNEL"), components: [] }); - const queue = client.player.getQueue(msg.guild.id); - if (queue) return msg.update({ content: interaction.translate("music/clips:ACTIVE_QUEUE"), components: [] }); - if (getVoiceConnection(msg.guild.id)) return msg.update({ content: interaction.translate("music/clips:ACTIVE_CLIP"), components: [] }); - if (!fs.existsSync(`./clips/${clip}.mp3`)) return msg.update({ content: interaction.translate("music/clips:NO_FILE", { file: clip }), components: [] }); + collector.on("collect", async i => { + 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: [] }); try { const connection = joinVoiceChannel({ channelId: voice.id, - guildId: msg.guild.id, - adapterCreator: msg.guild.voiceAdapterCreator + guildId: i.guild.id, + adapterCreator: i.guild.voiceAdapterCreator }); const resource = createAudioResource(fs.createReadStream(`./clips/${clip}.mp3`)); @@ -97,7 +99,7 @@ class Clips extends BaseCommand { console.error(error); } - await msg.update({ + await i.update({ content: interaction.translate("music/clips:PLAYING", { clip }), diff --git a/commands/NSFW/nsfw.js b/commands/NSFW/nsfw.js index b1ecddf7..254aa5b3 100644 --- a/commands/NSFW/nsfw.js +++ b/commands/NSFW/nsfw.js @@ -56,14 +56,16 @@ class NSFW extends BaseCommand { fetchReply: true }); + const filter = i => i.customId === "nsfw_select" && i.user.id === interaction.user.id; const collector = new InteractionCollector(client, { + filter, componentType: ComponentType.SelectMenu, message: msg, idle: 60 * 1000 }); - collector.on("collect", async msg => { - const tag = msg?.values[0]; + collector.on("collect", async i => { + const tag = i?.values[0]; const res = await fetch(`https://meme-api.herokuapp.com/gimme/${tag}`).then(response => response.json()); const embed = new EmbedBuilder() @@ -75,7 +77,7 @@ class NSFW extends BaseCommand { .setImage(res.url) .setTimestamp(); - await msg.update({ + await i.update({ embeds: [embed] }); }); diff --git a/commands/Owner/debug.js b/commands/Owner/debug.js index 6f71c6f8..09c2d5ae 100644 --- a/commands/Owner/debug.js +++ b/commands/Owner/debug.js @@ -27,7 +27,7 @@ class Debug extends BaseCommand { .setDescription(client.translate("owner/debug:TARGET")) .setRequired(true)) .addIntegerOption(option => option.setName("int") - .setDescription(client.translate("owner/debug:INT")) + .setDescription(client.translate("common:INT")) .setRequired(true)) ) .addSubcommand(subcommand => subcommand.setName("add") diff --git a/helpers/extenders.js b/helpers/extenders.js index 73bfcb2f..aa4f098d 100644 --- a/helpers/extenders.js +++ b/helpers/extenders.js @@ -1,5 +1,11 @@ const { Message, CommandInteraction } = require("discord.js"); +/** + * + * @param {String} key + * @param {Array} args + * @returns {String} + */ CommandInteraction.prototype.translate = function (key, args) { const language = this.client.translations.get(this.guild ? this.guild.data.language : "ru-RU"); if (!language) throw "Message: Invalid language set in data."; @@ -7,6 +13,13 @@ CommandInteraction.prototype.translate = function (key, args) { return language(key, args); }; +/** + * + * @param {String} key + * @param {Array} args + * @param {Array} options + * @returns {import("discord.js").BaseCommandInteraction} + */ CommandInteraction.prototype.replyT = function (key, args, options = {}) { let string = this.translate(key, args, this.guild ? this.guild.data.language : "ru-RU"); if (options.prefixEmoji) string = `${this.client.customEmojis[options.prefixEmoji]} | ${string}`; @@ -15,12 +28,26 @@ CommandInteraction.prototype.replyT = function (key, args, options = {}) { else return this.reply({ content: string, ephemeral: options.ephemeral || false }); }; +/** + * + * @param {String} key + * @param {Array} args + * @param {Array} options + * @returns {import("discord.js").BaseCommandInteraction} + */ CommandInteraction.prototype.error = function (key, args, options = {}) { options.prefixEmoji = "error"; return this.replyT(key, args, options); }; +/** + * + * @param {String} key + * @param {Array} args + * @param {Array} options + * @returns {import("discord.js").BaseCommandInteraction} + */ CommandInteraction.prototype.success = function (key, args, options = {}) { options.prefixEmoji = "success"; diff --git a/helpers/extractor.js b/helpers/extractor.js index 7b0637e5..edbecbdd 100644 --- a/helpers/extractor.js +++ b/helpers/extractor.js @@ -14,7 +14,7 @@ const Youtube = require("youtube-sr").default; thanks :) - -nize + -nize */ module.exports = { @@ -85,7 +85,7 @@ module.exports = { duration: spotifyTrack.duration_ms, thumbnail: info.image, async engine() { - return (await playdl.stream(await Youtube.search(`${info.artist} ${info.title} lyric`, {limit: 1, type: "video", safeSearch: true}).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; + return (await playdl.stream(await Youtube.search(`${info.artist} ${info.title} lyric`, { limit: 1, type: "video", safeSearch: true }).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; }, views: 0, author: info.artist, @@ -102,7 +102,7 @@ module.exports = { duration: track.duration_ms, thumbnail: track.album && track.album.images.length ? track.album.images[0].url : null, async engine() { - return (await playdl.stream(await Youtube.search(`${track.artists[0].name} ${track.name} lyric`, {limit: 1, type: "video", safeSearch: true}).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; + return (await playdl.stream(await Youtube.search(`${track.artists[0].name} ${track.name} lyric`, { limit: 1, type: "video", safeSearch: true }).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; }, views: 0, author: track.artists ? track.artists[0].name : null, @@ -131,7 +131,28 @@ module.exports = { query = query.split("&")[0]; } if (query.startsWith("https") && playdl.yt_validate(query) === "video") { - const info = await Youtube.search(query, {limit: 1, type: "video", safeSearch: true}); + if (query.includes("music.youtube")) { + const info = await playdl.video_info(query); + if(!info) + return resolve({ playlist: null, info: null }); + const track = { + title: info.video_details.title, + duration: info.video_details.duration, + thumbnail: info.video_details.thumbnails[0].url, + async engine() { + return (await playdl.stream(`https://music.youtube.com/watch?v=${info.video_details.id}`, { discordPlayerCompatibility : true })).stream; + }, + views: info.video_details.views, + author: info.video_details.channel.name, + description: "", + url: `https://music.youtube.com/watch?v=${info.video_details.id}`, + source: "youtube-music-custom" + }; + + return resolve({ playlist: null, info: [track] }); + } + + const info = await Youtube.search(query, { limit: 1, type: "video", safeSearch: true }); if(!info || !info.length) return resolve({ playlist: null, info: null }); @@ -158,7 +179,7 @@ module.exports = { duration: track.durationInSec * 1000, thumbnail: track.thumbnails ? track.thumbnails[0] ? track.thumbnails[0].url : null : null, async engine() { - return (await playdl.stream(await Youtube.search(track.url, {limit: 1, type: "video", safeSearch: true}).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; + return (await playdl.stream(await Youtube.search(track.url, { limit: 1, type: "video", safeSearch: true }).then(x => x[0] ? `https://youtu.be/${x[0].id}` : "https://youtu.be/Wch3gJG2GJ4"), { discordPlayerCompatibility : true })).stream; }, views: track.views, author: track.channel.name, diff --git a/languages/ru-RU/common.json b/languages/ru-RU/common.json index 22169cc4..657ae598 100644 --- a/languages/ru-RU/common.json +++ b/languages/ru-RU/common.json @@ -1,8 +1,9 @@ { "YES": "Да", "NO": "Нет", + "ACCEPT": "Принять", + "CANCEL": "Отменить", "NOT_DEFINED": "Не установлено", - "AND_MORE": "И т.д...", "AUTHOR": "Автор", "DATE": "Дата", "MISSING": "Отсутствует", @@ -51,6 +52,7 @@ "CONFIGURATION": "Настройки", "EMOJI": "Эмодзи", "IP": "IP адрес", + "INT": "Целое число", "LANGUAGE": "Язык", "CHANNEL": "Канал", "UPDATE": "Обновить", diff --git a/languages/ru-RU/general/emoji.json b/languages/ru-RU/general/emoji.json index f2dc10b5..1ade9a42 100644 --- a/languages/ru-RU/general/emoji.json +++ b/languages/ru-RU/general/emoji.json @@ -6,5 +6,6 @@ "NAME": "Название", "ANIMATED": "Анимирован", "ID": "ID", + "LINK": "Ссылка", "STANDART": "Стандартный эмодзи" } \ No newline at end of file diff --git a/languages/ru-RU/misc.json b/languages/ru-RU/misc.json index a9562dc7..f0fdbf88 100644 --- a/languages/ru-RU/misc.json +++ b/languages/ru-RU/misc.json @@ -1,7 +1,8 @@ { "CLICK_HERE": "Нажмите сюда, чтобы начать {{activity}} в {{channel}}", "TIMES_UP": "Время вышло! Используйте команду снова!", - "INVALID_YES_NO": "Отправьте `да` или `нет` (регистр не важен)!", + "SELECT_CANCELED": "Выбор отменён", + "INVALID_NUMBER_RANGE": "Укажите число от **{{min}}** до **{{max}}**!", "FORCE_STOP": "Игра принудительно окончена {{user}}, никто не победил!", "STATS_FOOTER": "● [Панель управления]({{dashboardLink}})\n● [Документация]({{docsLink}})\n● [Пригласить JaBa на свой сервер]({{inviteLink}})\n● [Поддержать]({{donateLink}}) (укажите ваш Discord тэг для выдачи ачивки, для других способов поддержки пишите в ЛС <@{{owner}}>)", "BOT_USER": "Вы не можете сделать это с ботом!", diff --git a/languages/ru-RU/moderation/clear.json b/languages/ru-RU/moderation/clear.json index 6ce6a0e6..eec4f635 100644 --- a/languages/ru-RU/moderation/clear.json +++ b/languages/ru-RU/moderation/clear.json @@ -1,9 +1,10 @@ { "DESCRIPTION": "Удалить сообщения!", "USAGE": "clear [кол-во_сообщений] (@пользователь)", - "EXAMPLES": "clear 10\nclear 10 @Jonny_Bro#4226\nclear all", - "MISSING_AMOUNT": "Укажите кол-во сообщений для удаления!", - "ALL_CONFIRM": "Все сообщения в канале будут удалены! Введите `confirm` для подтверждения", + "EXAMPLES": "clear 10\r 10 @Jonny_Bro#4226\nclear all", + "OPTION_NAN": "Укажите целое число больше 0 или `all`", + "OPTION": "Целое число / all", + "ALL_CONFIRM": "**Все сообщения в канале будут удалены! Вы уверены?**", "CHANNEL_CLEARED": "Канал очищен!", "CLEARED": "Было удалено **{{amount}}**!", "CLEARED_MEMBER": "Было удалено **{{amount}}** от **{{username}}**!" diff --git a/languages/ru-RU/moderation/giveaway.json b/languages/ru-RU/moderation/giveaway.json index 41d27ccf..d827c010 100644 --- a/languages/ru-RU/moderation/giveaway.json +++ b/languages/ru-RU/moderation/giveaway.json @@ -2,13 +2,16 @@ "DESCRIPTION": "Управление раздачами!", "USAGE": "giveaway [create/reroll/delete/end] [время] [кол-во победителей] (Дроп? true) [приз]", "EXAMPLES": "giveaway create 1d 2 100 рублей на карту!\ngiveaway create 1d 2 true 100 рублей на карту\ngiveaway reroll 597812898022031374", - "MISSING_STATUS": "Выберите действие: `create`, `reroll`, `end` или `delete`!", "INVALID_CREATE": "Какой-то из аргументов указан неверно, попробуйте снова!", + "GIVEAWAY_ID": "ID сообщения раздачи", + "WINNERS_COUNT": "Количество победителей", + "PRIZE": "Приз", + "ISDROP": "Это дроп?", "MISSING_ID": "Укажите ID сообщения раздачи!", - "NOT_FOUND": "Раздач с ID `{{messageID}}` не найдено!", - "NOT_FOUND_ENDED": "**Оконченных** раздач с ID `{{messageID}} не найдено!`!", - "MAX_DURATION": "Максимальная длительность раздачи - 15 дней.", - "MAX_COUNT": "Одновременно можно создать только 4 раздачи.", + "NOT_FOUND": "Раздач с ID `{{messageId}}` не найдено!", + "NOT_FOUND_ENDED": "**Оконченных** раздач с ID `{{messageId}} не найдено!`!", + "MAX_DURATION": "Максимальная длительность раздачи - 10 дней.", + "MAX_COUNT": "Одновременно можно создать только 5 раздач.", "TITLE": "🎉🎉 **РАЗДАЧА** 🎉🎉", "ENDED": "🎉🎉 **РАЗДАЧА ОКОНЧЕНА** 🎉🎉", "TIME_REMAINING": "Оставшееся время: **{duration}**!", diff --git a/languages/ru-RU/moderation/poll.json b/languages/ru-RU/moderation/poll.json index 01002758..ffd953a7 100644 --- a/languages/ru-RU/moderation/poll.json +++ b/languages/ru-RU/moderation/poll.json @@ -2,7 +2,12 @@ "DESCRIPTION": "Запустить опрос в текущем канале!", "USAGE": "poll [вопрос]", "EXAMPLES": "poll Земля плоская?", - "MISSING_QUESTION": "Введите вопрос!", + "QUESTION": "Текст вопроса", + "HERE": "@here", + "EVERYONE": "@everyone", + "NOTHING": "Без упоминания", + "SELECT_MENTION": "Выберите упоминание:", + "POLL_SENDED": "Опрос отправлен", "REACT": "Отреагируйте {{success}} или {{error}}!", "TITLE": "📊 Опрос:" } \ No newline at end of file diff --git a/languages/ru-RU/moderation/unban.json b/languages/ru-RU/moderation/unban.json index 4466a188..ba9aeb10 100644 --- a/languages/ru-RU/moderation/unban.json +++ b/languages/ru-RU/moderation/unban.json @@ -1,8 +1,8 @@ { - "DESCRIPTION": "Разбанить пользователя на сервере!", + "DESCRIPTION": "Разбанить пользователя на сервере", "USAGE": "unban [ID]", "EXAMPLES": "unban 281361531411890186", - "MISSING_ID": "Укажите ID пользователя!", - "NOT_BANNED": "**{{username}}** не забанен!", - "UNBANNED": "**{{username}}** был разбанен на сервере **{{server}}**!" + "ID": "ID пользователя", + "NOT_BANNED": "Пользователь с ID **{{id}}** не найден", + "UNBANNED": "**{{id}}** разбанен!" } \ No newline at end of file diff --git a/languages/ru-RU/music/play.json b/languages/ru-RU/music/play.json index f5b1c071..fabd257b 100644 --- a/languages/ru-RU/music/play.json +++ b/languages/ru-RU/music/play.json @@ -2,7 +2,7 @@ "DESCRIPTION": "Начать воспроизведение трека", "USAGE": "play [название-трека/ссылка]", "EXAMPLES": "play Never Gonna Give You Up", - "QUERY": "Название/Прямая ссылка/Ссылка на YouTube, Spotify или SoundCloud", + "QUERY": "Название / Прямая ссылка / Ссылка на YouTube, Spotify или SoundCloud", "NO_VOICE_CHANNEL": "Вы должны находиться в голосовом канале!", "VOICE_CHANNEL_CONNECT": "Я не могу присоедениться к вашему голосовому каналу!", "RESULTS_FOOTER": "Укажите число от 1 до 10 (без префикса).", diff --git a/languages/ru-RU/owner/debug.json b/languages/ru-RU/owner/debug.json index 3d19e106..6cea945a 100644 --- a/languages/ru-RU/owner/debug.json +++ b/languages/ru-RU/owner/debug.json @@ -5,7 +5,6 @@ "TYPE": "Тип данных", "SET": "Установить значение", "ADD": "Добавить к значению", - "INT": "Целое число", "SUCCESS_LEVEL": "Уровень пользователя **{{username}}** изменён на **{{amount}}**!", "SUCCESS_XP": "XP пользователя **{{username}}** изменён на **{{amount}}**!", "SUCCESS_CREDITS": "Кредиты пользователя **{{username}}** изменены на **{{amount}}**!",