v4.4.0 - https:/dash.jababot.ru/updates

This commit is contained in:
Jonny_Bro (Nikita) 2023-11-04 16:56:10 +05:00
parent 82a92f0caa
commit a9edce1b75
30 changed files with 580 additions and 245 deletions

View file

@ -38,14 +38,21 @@ class JaBa extends Client {
this.player.extractors.loadDefault();
this.player.events.on("playerStart", 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) });
const m = (await queue.metadata.channel.send({
content: this.translate("music/play:NOW_PLAYING", { songName: track.title }, queue.metadata.channel.guild.data.language),
})).id;
if (track.durationMS > 1)
setTimeout(() => {
if (m.deletable) m.delete();
const message = queue.metadata.channel.messages.cache.get(m);
if (message.deletable) message.delete();
}, track.durationMS);
else
setTimeout(() => {
if (m.deletable) m.delete();
const message = queue.metadata.channel.messages.cache.get(m);
if (message.deletable) message.delete();
}, 5 * 60 * 1000); // m * s * ms
});
this.player.events.on("emptyQueue", queue => queue.metadata.channel.send(this.translate("music/play:QUEUE_ENDED", null, queue.metadata.channel.guild.data.language)));
@ -227,10 +234,9 @@ class JaBa extends Client {
* @param {String} locale Language
*/
translate(key, args, locale = this.defaultLanguage) {
const language = this.translations.get(locale);
if (!language) throw "Invalid language set in data.";
const lang = this.translations.get(locale);
return language(key, args);
return lang(key, args);
}
/**

View file

@ -46,7 +46,7 @@ class ImportMee6 extends BaseCommand {
content: interaction.translate("owner/debug:SUCCESS_LEVEL", {
user: interaction.member.toString(),
amount: level,
}),
}, "success"),
});
}
}

View file

@ -68,10 +68,9 @@ class Memes extends BaseCommand {
),
);
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("memes_select").setPlaceholder(client.translate("common:NOTHING_SELECTED")).addOptions(tags));
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("memes_select").setPlaceholder(interaction.translate("common:NOTHING_SELECTED")).addOptions(tags));
await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"),
components: [row],
});
}

View file

@ -207,7 +207,7 @@ async function changeSetting(interaction, setting, state, channel, guildData) {
await guildData.save();
return interaction.reply({
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: **${interaction.translate("common:DISABLED")}**`,
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`, null, "success")}: **${interaction.translate("common:DISABLED", null, "success")}**`,
ephemeral: true,
});
} else {
@ -226,7 +226,7 @@ async function changeSetting(interaction, setting, state, channel, guildData) {
} else
return interaction.reply({
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: ${
guildData.plugins[setting] ? `**${interaction.translate("common:ENABLED")}** (<#${guildData.plugins[setting]}>)` : `**${interaction.translate("common:DISABLED")}**`
guildData.plugins[setting] ? `**${interaction.translate("common:ENABLED", null, "success")}** (<#${guildData.plugins[setting]}>)` : `**${interaction.translate("common:DISABLED", null, "success")}**`
}`,
ephemeral: true,
});

View file

@ -102,7 +102,7 @@ class Selectroles extends BaseCommand {
}
interaction.reply({
content: interaction.translate("administration/selectroles:ROLES_UPDATED"),
content: interaction.translate("administration/selectroles:ROLES_UPDATED", null, "success"),
ephemeral: true,
});
}

View file

@ -167,18 +167,16 @@ class Marry extends BaseCommand {
content: interaction.translate("economy/marry:SUCCESS", {
creator: interaction.member.toString(),
partner: member.toString(),
}),
}, "success"),
components: [],
});
} else {
return interaction.editReply({
} else return interaction.editReply({
content: interaction.translate("economy/marry:DENIED", {
creator: interaction.member.toString(),
partner: member.toString(),
}),
}, "error"),
components: [],
});
}
});
}
}

View file

@ -0,0 +1,46 @@
const { ContextMenuCommandBuilder, ApplicationCommandType } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class AvatarContext extends BaseCommand {
/**
*
* @param {import("../../base/JaBa")} client
*/
constructor() {
super({
command: new ContextMenuCommandBuilder()
.setName("Avatar")
.setType(ApplicationCommandType.User)
.setDMPermission(false),
aliases: [],
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/JaBa")} client
*/
async onLoad() {
//...
}
/**
*
* @param {import("../../base/JaBa")} client
* @param {import("discord.js").UserContextMenuCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
const avatar = interaction.targetUser.avatarURL({ size: 2048 });
interaction.reply({
files: [
{
attachment: avatar,
},
],
});
}
}
module.exports = AvatarContext;

View file

@ -29,7 +29,7 @@ class Boosters extends BaseCommand {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
if (interaction.customId.includes("boosters_")) {
if (interaction.customId.startsWith("boosters_")) {
const guildData = client.findOrCreateGuild(interaction.guildId),
boosters = (await interaction.guild.members.fetch()).filter(m => m.premiumSince),
embeds = generateBoostersEmbeds(client, interaction, boosters, guildData);
@ -41,7 +41,7 @@ class Boosters extends BaseCommand {
new ButtonBuilder().setCustomId("boosters_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
);
let currentPage = 0;
let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0;
if (interaction.customId === "boosters_prev_page") {
await interaction.deferUpdate();

View file

@ -108,10 +108,9 @@ class Help extends BaseCommand {
};
});
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("help_category_select").setPlaceholder(client.translate("common:NOTHING_SELECTED")).addOptions(categoriesRows));
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("help_category_select").setPlaceholder(interaction.translate("common:NOTHING_SELECTED")).addOptions(categoriesRows));
await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"),
fetchReply: true,
components: [row],
});

View file

@ -1,14 +1,18 @@
const { ContextMenuCommandBuilder, ModalBuilder, EmbedBuilder, ActionRowBuilder, TextInputBuilder, ApplicationCommandType, PermissionsBitField, TextInputStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Warn extends BaseCommand {
class WarnContext extends BaseCommand {
/**
*
* @param {import("../../base/JaBa")} client
*/
constructor() {
super({
command: new ContextMenuCommandBuilder().setName("warn").setType(ApplicationCommandType.User).setDMPermission(false).setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages),
command: new ContextMenuCommandBuilder()
.setName("Warn")
.setType(ApplicationCommandType.User)
.setDMPermission(false)
.setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages),
aliases: [],
dirname: __dirname,
ownerOnly: false,
@ -200,4 +204,4 @@ class Warn extends BaseCommand {
}
}
module.exports = Warn;
module.exports = WarnContext;

View file

@ -58,12 +58,20 @@ class Loop extends BaseCommand {
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
const translated = {
"AUTOPLAY": interaction.translate("music/loop:AUTOPLAY_ENABLED", null, "success"),
"QUEUE": interaction.translate("music/loop:QUEUE_ENABLED", null, "success"),
"TRACK": interaction.translate("music/loop:TRACK_ENABLED", null, "success"),
"OFF": interaction.translate("music/loop:LOOP_DISABLED", null, "success"),
"0": interaction.translate("music/loop:LOOP_DISABLED", null, "success"),
};
const type = interaction.options.getString("option"),
mode = type === "3" ? QueueRepeatMode.AUTOPLAY : type === "2" ? QueueRepeatMode.QUEUE : type === "1" ? QueueRepeatMode.TRACK : QueueRepeatMode.OFF;
mode = QueueRepeatMode[type];
queue.setRepeatMode(mode);
interaction.success(`music/loop:${type === "3" ? "AUTOPLAY_ENABLED" : type === "2" ? "QUEUE_ENABLED" : type === "1" ? "TRACK_ENABLED" : "LOOP_DISABLED"}`);
interaction.reply({ content: translated[type] });
}
}

View file

@ -1,4 +1,4 @@
const { SlashCommandBuilder, EmbedBuilder } = require("discord.js"),
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder, StringSelectMenuOptionBuilder } = require("discord.js"),
{ QueueRepeatMode } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand");
@ -26,8 +26,156 @@ class Nowplaying extends BaseCommand {
*
* @param {import("../../base/JaBa")} client
*/
async onLoad() {
//...
async onLoad(client) {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
if (interaction.customId.startsWith("nowp_")) {
const voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL");
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING");
const row1 = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("nowp_prev_track").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("nowp_loop").setStyle(ButtonStyle.Secondary).setEmoji("🔁"),
new ButtonBuilder().setCustomId("nowp_add_track").setStyle(ButtonStyle.Success).setEmoji("▶️"),
new ButtonBuilder().setCustomId("nowp_next_track").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
);
const row2 = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("nowp_queue").setStyle(ButtonStyle.Secondary).setEmoji(""),
new ButtonBuilder().setCustomId("nowp_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
);
if (interaction.customId === "nowp_prev_track") {
await interaction.deferUpdate();
if (queue.history.isEmpty()) return interaction.followUp({ content: interaction.translate("music/back:NO_PREV_SONG", null, "error"), ephemeral: true });
queue.history.back();
await interaction.followUp({ content: interaction.translate("music/back:SUCCESS", null, "success"), ephemeral: true });
const embed = await updateEmbed(interaction, queue);
interaction.editReply({
embeds: [embed],
});
} else if (interaction.customId === "nowp_loop") {
await interaction.deferUpdate();
const selectMenu = new StringSelectMenuBuilder()
.setCustomId("nowp_select")
.setPlaceholder(interaction.translate("common:NOTHING_SELECTED"))
.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel(interaction.translate("music/loop:AUTOPLAY"))
.setValue("3"),
new StringSelectMenuOptionBuilder()
.setLabel(interaction.translate("music/loop:QUEUE"))
.setValue("2"),
new StringSelectMenuOptionBuilder()
.setLabel(interaction.translate("music/loop:TRACK"))
.setValue("1"),
new StringSelectMenuOptionBuilder()
.setLabel(interaction.translate("music/loop:DISABLE"))
.setValue("0"),
);
const selectRow = new ActionRowBuilder().addComponents(selectMenu),
msg = await interaction.followUp({
components: [selectRow],
ephemeral: true,
});
const filter = i => i.user.id === interaction.user.id,
collected = await msg.awaitMessageComponent({ filter, time: 10 * 1000 }),
mode = QueueRepeatMode[collected.values[0]],
translated = {
"AUTOPLAY": interaction.translate("music/loop:AUTOPLAY_ENABLED", null, "success"),
"QUEUE": interaction.translate("music/loop:QUEUE_ENABLED", null, "success"),
"TRACK": interaction.translate("music/loop:TRACK_ENABLED", null, "success"),
"OFF": interaction.translate("music/loop:LOOP_DISABLED", null, "success"),
"0": interaction.translate("music/loop:LOOP_DISABLED", null, "success"),
};
await collected.deferUpdate();
queue.setRepeatMode(mode);
await interaction.followUp({ content: translated[mode] });
const embed = await updateEmbed(interaction, queue);
interaction.editReply({
embeds: [embed],
});
} else if (interaction.customId === "nowp_add_track") {
await interaction.deferUpdate();
await interaction.followUp({
content: interaction.translate("music/nowplaying:LINK"),
ephemeral: true,
});
const filter = m => m.author.id === interaction.user.id && m.content.startsWith("http"),
collected = (await interaction.channel.awaitMessages({ filter, time: 10 * 1000, max: 1 })).first(),
query = collected.content.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g)[0],
searchResult = await client.player.search(query, {
requestedBy: interaction.user,
});
if (!searchResult.hasTracks()) return interaction.error("music/play:NO_RESULT", { query: query }, { edit: true });
else queue.addTrack(searchResult);
if (collected.deletable) collected.delete();
await interaction.followUp({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title,
}, "success"),
});
const embed = await updateEmbed(interaction, queue);
interaction.editReply({
embeds: [embed],
});
} else if (interaction.customId === "nowp_next_track") {
await interaction.deferUpdate();
queue.node.skip();
await interaction.followUp({ content: interaction.translate("music/skip:SUCCESS", null, "success"), ephemeral: true });
const embed = await updateEmbed(interaction, queue);
interaction.editReply({
embeds: [embed],
});
} else if (interaction.customId === "nowp_queue") {
await interaction.deferUpdate();
client.commands.get("queue").execute(client, interaction);
} else if (interaction.customId === "nowp_stop") {
await interaction.deferUpdate();
row1.components.forEach(component => {
component.setDisabled(true);
});
row2.components.forEach(component => {
component.setDisabled(true);
});
return interaction.editReply({
components: [row1, row2],
});
}
}
});
}
/**
*
@ -35,13 +183,50 @@ class Nowplaying extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction, data) {
async execute(client, interaction) {
await interaction.deferReply();
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
const row1 = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("nowp_prev_track").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("nowp_loop").setStyle(ButtonStyle.Secondary).setEmoji("🔁"),
new ButtonBuilder().setCustomId("nowp_add_track").setStyle(ButtonStyle.Success).setEmoji("▶️"),
new ButtonBuilder().setCustomId("nowp_next_track").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
);
const row2 = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("nowp_queue").setStyle(ButtonStyle.Secondary).setEmoji(""),
new ButtonBuilder().setCustomId("nowp_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
);
const embed = await updateEmbed(interaction, queue);
interaction.editReply({
embeds: [embed],
components: [row1, row2],
});
}
}
/**
*
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {import("discord-player").GuildQueue} queue
* @returns
*/
async function updateEmbed(interaction, queue) {
const progressBar = queue.node.createProgressBar(),
track = queue.currentTrack;
track = queue.currentTrack,
data = await interaction.client.guildsData.findOne({ id: interaction.guildId }),
translated = {
"AUTOPLAY": interaction.translate("music/nowplaying:AUTOPLAY"),
"QUEUE": interaction.translate("music/nowplaying:QUEUE"),
"TRACK": interaction.translate("music/nowplaying:TRACK"),
"OFF": interaction.translate("common:DISABLED"),
"0": interaction.translate("common:DISABLED"),
};
const embed = new EmbedBuilder()
.setAuthor({
@ -62,7 +247,7 @@ class Nowplaying extends BaseCommand {
{ name: "\u200B", value: "\u200B", inline: true },
{
name: interaction.translate("common:VIEWS"),
value: track.raw.live ? "" : new Intl.NumberFormat(client.languages.find(language => language.name === data.guildData.language).moment, { notation: "standard" }).format(track.raw.views),
value: track.raw.live ? "Live" : new Intl.NumberFormat(interaction.client.languages.find(language => language.name === data.language).moment, { notation: "standard" }).format(track.raw.views),
inline: true,
},
{
@ -76,25 +261,14 @@ class Nowplaying extends BaseCommand {
},
{
name: "\u200b",
value: `${interaction.translate("music/nowplaying:REPEAT")}: \`${
queue.repeatMode === QueueRepeatMode.AUTOPLAY
? interaction.translate("music/nowplaying:AUTOPLAY")
: queue.repeatMode === QueueRepeatMode.QUEUE
? interaction.translate("music/nowplaying:QUEUE")
: queue.repeatMode === QueueRepeatMode.TRACK
? interaction.translate("music/nowplaying:TRACK")
: interaction.translate("common:DISABLED")
}\``,
value: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\``,
},
])
.setColor(client.config.embed.color)
.setFooter(client.config.embed.footer)
.setColor(interaction.client.config.embed.color)
.setFooter(interaction.client.config.embed.footer)
.setTimestamp();
interaction.editReply({
embeds: [embed],
});
}
return embed;
}
module.exports = Nowplaying;

80
commands/Music/play.c.js Normal file
View file

@ -0,0 +1,80 @@
const { ContextMenuCommandBuilder, ApplicationCommandType, PermissionsBitField } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class PlayContext extends BaseCommand {
/**
*
* @param {import("../../base/JaBa")} client
*/
constructor() {
super({
command: new ContextMenuCommandBuilder()
.setName("Add to Queue")
.setType(ApplicationCommandType.Message)
.setDMPermission(false),
aliases: [],
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/JaBa")} client
*/
async onLoad() {
//...
}
/**
*
* @param {import("../../base/JaBa")} client
* @param {import("discord.js").MessageContextMenuCommandInteraction} interaction
* @param {Object} data
*/
async execute(client, interaction) {
await interaction.deferReply();
const query = interaction.targetMessage.content.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g)[0],
voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
const perms = voice.permissionsFor(client.user);
if (!perms.has(PermissionsBitField.Flags.Connect) || !perms.has(PermissionsBitField.Flags.Speak)) return interaction.error("music/play:VOICE_CHANNEL_CONNECT", null, { edit: true });
const searchResult = await client.player.search(query, {
requestedBy: interaction.user,
});
if (!searchResult.hasTracks()) return interaction.error("music/play:NO_RESULT", { query }, { edit: true });
else {
const { queue } = await client.player.play(interaction.member.voice.channel, searchResult, {
nodeOptions: {
metadata: {
client,
channel: interaction.channel,
requestedBy: interaction.user,
},
},
selfDeaf: true,
leaveOnEnd: false,
leaveOnStop: true,
skipOnNoStream: true,
maxSize: 200,
maxHistorySize: 50,
});
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title,
}, "success"),
});
if (client.player.nodes.get(interaction.guildId).currentTrack.url === query && query.match(/&t=[[0-9]+/g) !== null) {
const time = query.match(/&t=[[0-9]+/g)[0].split("=")[1];
queue.node.seek(time * 1000);
}
}
}
}
module.exports = PlayContext;

View file

@ -80,16 +80,16 @@ class Play extends BaseCommand {
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title,
}),
}, "success"),
});
if (query.match(/&t=[[0-9]+/g) != null) {
// TODO: Seeks currently playing D:
if (query.match(/&t=[[0-9]+/g) !== null) {
const time = query.match(/&t=[[0-9]+/g)[0].split("=")[1];
queue.node.seek(time * 1000);
}
}
}
/**
@ -100,8 +100,9 @@ class Play extends BaseCommand {
*/
async autocompleteRun(client, interaction) {
const query = interaction.options.getString("query");
if (query === "") return;
if (query.includes("http")) return interaction.respond([
if (query.startsWith("http")) return interaction.respond([
{
name: "Current link",
value: query,

View file

@ -1,5 +1,4 @@
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"),
{ QueueRepeatMode } = require("discord-player");
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Queue extends BaseCommand {
@ -26,8 +25,94 @@ class Queue extends BaseCommand {
*
* @param {import("../../base/JaBa")} client
*/
async onLoad() {
//...
async onLoad(client) {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
if (interaction.customId.startsWith("queue_")) {
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING");
const { embeds, size } = generateQueueEmbeds(client, interaction, queue);
let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0;
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("queue_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("queue_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
new ButtonBuilder().setCustomId("queue_jump_page").setStyle(ButtonStyle.Secondary).setEmoji("↗️"),
new ButtonBuilder().setCustomId("queue_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
);
if (interaction.customId === "queue_prev_page") {
await interaction.deferUpdate();
if (currentPage !== 0) {
--currentPage;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${size}**`,
embeds: [embeds[currentPage]],
components: [row],
});
}
} else if (interaction.customId === "queue_next_page") {
await interaction.deferUpdate();
if (currentPage < size - 1) {
currentPage++;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${size}**`,
embeds: [embeds[currentPage]],
components: [row],
});
}
} else if (interaction.customId === "queue_jump_page") {
await interaction.deferUpdate();
const selectMenu = new StringSelectMenuBuilder()
.setCustomId("queue_select")
.setPlaceholder(interaction.translate("common:NOTHING_SELECTED"));
for (let i = 0; i < size; i++) {
selectMenu.addOptions(
new StringSelectMenuOptionBuilder()
.setLabel(`${i + 1}`)
.setValue(`${i}`),
);
}
const selectRow = new ActionRowBuilder().addComponents(selectMenu),
msg = await interaction.followUp({
components: [selectRow],
ephemeral: true,
});
const filter = i => i.user.id === interaction.user.id,
collected = await msg.awaitMessageComponent({ filter, time: 10 * 1000 }),
page = Number(collected.values[0]);
await collected.deferUpdate();
return interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${page + 1}**/**${size}**`,
embeds: [embeds[page]],
components: [row],
});
} else if (interaction.customId === "queue_stop") {
await interaction.deferUpdate();
row.components.forEach(component => {
component.setDisabled(true);
});
return interaction.editReply({
components: [row],
});
}
}
});
}
/**
*
@ -39,99 +124,25 @@ class Queue extends BaseCommand {
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING");
let currentPage = 0;
let embeds = generateQueueEmbeds(client, interaction, queue);
const row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("queue_prev_page").setLabel(interaction.translate("music/queue:PREV_PAGE")).setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("queue_next_page").setLabel(interaction.translate("music/queue:NEXT_PAGE")).setStyle(ButtonStyle.Primary).setEmoji("➡️"),
new ButtonBuilder().setCustomId("queue_jump_page").setLabel(interaction.translate("music/queue:JUMP_PAGE")).setStyle(ButtonStyle.Secondary).setEmoji("↗️"),
new ButtonBuilder().setCustomId("queue_stop").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
const { embeds, size } = generateQueueEmbeds(client, interaction, queue),
row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("queue_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("queue_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
new ButtonBuilder().setCustomId("queue_jump_page").setStyle(ButtonStyle.Secondary).setEmoji("↗️"),
new ButtonBuilder().setCustomId("queue_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
);
if (interaction.customId) return await interaction.followUp({
content: `${interaction.translate("common:PAGE")}: **1**/**${size}**`,
embeds: [embeds[0]],
components: [row],
});
await interaction.reply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
content: `${interaction.translate("common:PAGE")}: **1**/**${size}**`,
embeds: [embeds[0]],
components: [row],
});
const filter = i => i.user.id === interaction.user.id;
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: 20 * 1000 });
collector.on("collect", async i => {
if (i.isButton()) {
if (i.customId === "queue_prev_page") {
i.deferUpdate();
if (embeds != generateQueueEmbeds(client, interaction, queue)) embeds = generateQueueEmbeds(client, interaction, queue);
if (currentPage !== 0) {
--currentPage;
interaction.editReply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row],
});
}
} else if (i.customId === "queue_next_page") {
i.deferUpdate();
if (embeds != generateQueueEmbeds(client, interaction, queue)) embeds = generateQueueEmbeds(client, interaction, queue);
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 === "queue_jump_page") {
i.deferUpdate();
if (embeds != generateQueueEmbeds(client, interaction, queue)) embeds = generateQueueEmbeds(client, interaction, queue);
const msg = await interaction.followUp({
content: interaction.translate("misc:JUMP_TO_PAGE", {
length: embeds.length,
}),
fetchReply: true,
});
const filter = res => {
return res.author.id === interaction.user.id && !isNaN(res.content);
};
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 === "queue_stop") {
i.deferUpdate();
collector.stop();
}
}
});
collector.on("end", () => {
row.components.forEach(component => {
component.setDisabled(true);
});
return interaction.editReply({
components: [row],
});
});
}
}
@ -144,7 +155,14 @@ class Queue extends BaseCommand {
*/
function generateQueueEmbeds(client, interaction, queue) {
const embeds = [],
currentTrack = queue.currentTrack;
currentTrack = queue.currentTrack,
translated = {
"AUTOPLAY": interaction.translate("music/nowplaying:AUTOPLAY"),
"QUEUE": interaction.translate("music/nowplaying:QUEUE"),
"TRACK": interaction.translate("music/nowplaying:TRACK"),
"OFF": interaction.translate("common:DISABLED"),
"0": interaction.translate("common:DISABLED"),
};
let k = 10;
@ -154,22 +172,14 @@ function generateQueueEmbeds(client, interaction, queue) {
.setThumbnail(currentTrack.thumbnail)
.setColor(interaction.client.config.embed.color)
.setDescription(
`${interaction.translate("music/nowplaying:REPEAT")}: \`${
queue.repeatMode === QueueRepeatMode.AUTOPLAY
? interaction.translate("music/nowplaying:AUTOPLAY")
: queue.repeatMode === QueueRepeatMode.QUEUE
? interaction.translate("music/nowplaying:QUEUE")
: queue.repeatMode === QueueRepeatMode.TRACK
? interaction.translate("music/nowplaying:TRACK")
: interaction.translate("common:DISABLED")
}\`\n${currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`}\n> ${interaction.translate("music/queue:ADDED")} ${
currentTrack.requestedBy
}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`,
`${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${
currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`
}\n> ${interaction.translate("music/queue:ADDED")} ${currentTrack.requestedBy}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`,
)
.setTimestamp();
embeds.push(embed);
return embeds;
return { embeds: embeds, size: embeds.length };
}
for (let i = 0; i < queue.getSize(); i += 10) {
@ -184,15 +194,9 @@ function generateQueueEmbeds(client, interaction, queue) {
.setThumbnail(currentTrack.thumbnail)
.setColor(interaction.client.config.embed.color)
.setDescription(
`${interaction.translate("music/nowplaying:REPEAT")}: \`${
queue.repeatMode === QueueRepeatMode.AUTOPLAY
? interaction.translate("music/nowplaying:AUTOPLAY")
: queue.repeatMode === QueueRepeatMode.QUEUE
? interaction.translate("music/nowplaying:QUEUE")
: queue.repeatMode === QueueRepeatMode.TRACK
? interaction.translate("music/nowplaying:TRACK")
: interaction.translate("common:DISABLED")
}\`\n${currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`}\n> ${interaction.translate("music/queue:ADDED")} ${
`${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${
currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`
}\n * ${interaction.translate("music/queue:ADDED")} ${
currentTrack.requestedBy
}\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`,
)
@ -201,7 +205,7 @@ function generateQueueEmbeds(client, interaction, queue) {
embeds.push(embed);
}
return embeds;
return { embeds: embeds, size: embeds.length };
}
module.exports = Queue;

View file

@ -70,7 +70,7 @@ class NSFW extends BaseCommand {
),
);
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("nsfw_select").setPlaceholder(client.translate("common:NOTHING_SELECTED")).addOptions(tags));
const row = new ActionRowBuilder().addComponents(new StringSelectMenuBuilder().setCustomId("nsfw_select").setPlaceholder(interaction.translate("common:NOTHING_SELECTED")).addOptions(tags));
await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"),

View file

@ -61,7 +61,7 @@ class CloseTicket extends BaseCommand {
const button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger);
const row = new ActionRowBuilder().addComponents(button);
await interaction.reply({
await interaction.editReply({
embeds: [embed],
components: [row],
});

@ -1 +1 @@
Subproject commit 58c2082074c0955cfafd9ebddb9ad694621df0a1
Subproject commit 2826563af194effcb0469278ab3c38aa27bc2e82

View file

@ -17,11 +17,11 @@ const locales = {
module.exports.load = async client => {
const commands = client.commands.map(v => {
return {
_category: v.category,
commandName: v.command.name,
commandDescription: client.translate(`${v.category.toLowerCase()}/${v.command.name}:DESCRIPTION`),
commandUsage: client.translate(`${v.category.toLowerCase()}/${v.command.name}:USAGE`),
commandAlias: "",
_category: v.category,
};
});
let categories = [];
@ -48,11 +48,6 @@ module.exports.load = async client => {
id: client.config.userId,
secret: client.config.dashboard.secret,
},
// SSL: {
// enabled: false,
// key: fs.readFileSync(`${__dirname}/../jababot-cloudflare.key`, "utf-8"),
// cert: fs.readFileSync(`${__dirname}/../jababot-cloudflare.crt`, "utf-8"),
// },
cookiesSecret: client.config.dashboard.secret,
domain: client.config.dashboard.domain,
redirectUri: `${client.config.dashboard.domain}/discord/callback`,

View file

@ -1,11 +1,24 @@
# Обновления JaBa
## v4.4.0
* Добавлено
* Контекстная команда *Add to Queue* - Позволяет добавить в очередь трек/плейлист из сообщения.\
ПКМ на сообщение -> Приложения -> Add to Queue.\
Работает даже если в сообщении есть не только ссылка `Попробуй это: <ссылка>` или ссылка встроенна в текст `[текст](<ссылка>)`.
* Контекстная комана *Avatar* - Позволет получить аватар пользователя\
Работает так же как и *Add to Queue*, только нужно нажать на пользователя.
* Изменено
* Переписаны команды *queue*, *play*, *nowplaying*.\
В *nowplaying* добавлен дополнительный функционал в виде кнопок.
## v4.3.6
Скоро перепишу музыкальные команды, будет интересно, честно =)
* Изменено
* Переписал команды которые используют кнопки и списки, многие из них теперь будут отвечать даже после перезагрузки бота.
* Переписаны команды которые используют кнопки и списки, многие из них теперь будут отвечать даже после перезагрузки бота.
## v4.3.5
@ -147,9 +160,9 @@
### v4.1.15
* Изменения
* Переписана команда *config*.
* Теперь с её помощью можно просматривать и изменять настройки сервера.
* Использование смотрите в *help*.
* Переписана команда *config*.\
Теперь с её помощью можно просматривать и изменять настройки сервера.\
Использование смотрите в *help*.
* Удалено
* Команды *setbirthdays*, *setmodlogs*, *setnews*, *setreports*, *setsuggests*.
@ -157,9 +170,9 @@
### v4.1.14
* Добавлено
* Команда *selectroles* - Возможность выбора необязательных ролей пользователями.
* Сначала необходимо создать сообщение через */selectroles message text:<Ваш текст>*.
* После того как сообщение будет создано бот даст подсказку как добавлять роли к списку, следуйте инструкции.
* Команда *selectroles* - Возможность выбора необязательных ролей пользователями.\
Сначала необходимо создать сообщение через */selectroles message text:<Ваш текст>*.\
После того как сообщение будет создано бот даст подсказку как добавлять роли к списку, следуйте инструкции.
* Изменения
* Украинский перевод полностью обновлён.
@ -222,7 +235,8 @@
### v4.1.6
* Изменения
* Изменён способ указания типа повтора в *loop*. Теперь вы указываете тип аргументом (подсказки имеются), а не из выпадающего списка в отдельном сообщении. Это одновременно удобно, быстро и меньше кода =)
* Изменён способ указания типа повтора в *loop*.\
Теперь вы указываете тип аргументом (подсказки имеются), а не из выпадающего списка в отдельном сообщении. Это одновременно удобно, быстро и кода меньше =)
* Исправления
* Фиксы в *tictactoe*.
@ -293,7 +307,8 @@
* Перенесена категория *Administration*.
* Исправления
* Изменён способ получения музыки. На данный момент не работает Spotify, в будущих обновлениях постараюсь вернуть, но это не точно.
* Изменён способ получения музыки.\
На данный момент не работает Spotify, в будущих обновлениях постараюсь вернуть, но это не точно.
* Панель управления снова работает.
* Множество мелких правок.

View file

@ -4,15 +4,15 @@ User.prototype.getUsername = function () {
return this.discriminator === "0" ? this.username : this.tag;
};
BaseInteraction.prototype.translate = function (key, args) {
const language = this.client.translations.get(this.guild ? this.guild.data.language : "en-US");
if (!language) throw "Interaction: Invalid language set in data.";
BaseInteraction.prototype.translate = function (key, args, emoji) {
const lang = this.client.translations.get(this.guild.data.language ?? "en-US");
const string = emoji ? `${this.client.customEmojis[emoji]} | ${lang(key, args)}` : lang(key, args);
return language(key, args);
return string;
};
BaseInteraction.prototype.replyT = function (key, args, options = {}) {
const translated = this.translate(key, args, this.guild ? this.guild.data.language : "en-US");
const translated = this.translate(key, args, this.guild.data.language ?? "en-US");
const string = options.prefixEmoji ? `${this.client.customEmojis[options.prefixEmoji]} | ${translated}` : translated;
if (options.edit) return this.editReply({ content: string, ephemeral: options.ephemeral || false });
@ -31,15 +31,15 @@ BaseInteraction.prototype.error = function (key, args, options = {}) {
return this.replyT(key, args, options);
};
Message.prototype.translate = function (key, args) {
const language = this.client.translations.get(this.guild ? this.guild.data.language : "en-US");
if (!language) throw "Message: Invalid language set in data.";
Message.prototype.translate = function (key, args, emoji) {
const lang = this.client.translations.get(this.guild.data.language ?? "en-US");
const string = emoji ? `${this.client.customEmojis[emoji]} | ${lang(key, args)}` : lang(key, args);
return language(key, args);
return string;
};
Message.prototype.replyT = function (key, args, options = {}) {
const translated = this.translate(key, args, this.guild ? this.guild.data.language : "en-US");
const translated = this.translate(key, args, this.guild.data.language ?? "en-US");
const string = options.prefixEmoji ? `${this.client.customEmojis[options.prefixEmoji]} | ${translated}` : translated;
if (options.edit) return this.edit({ content: string, allowedMentions: { repliedUser: options.mention ? true : false } });

View file

@ -32,6 +32,7 @@
"IP": "IP Address",
"JOINED": "Joined",
"LANGUAGE": "Language",
"LINK": "Link",
"LEVEL": "Level",
"MONEY": "Money",
"MEMBER": "Member",

View file

@ -3,6 +3,7 @@
"USAGE": "",
"EXAMPLES": "nowplaying",
"CURRENTLY_PLAYING": "Currently playing",
"LINK": "Send a link in chat",
"T_TITLE": "Title",
"T_AUTHOR": "Author",
"T_DURATION": "Duration",

View file

@ -32,6 +32,7 @@
"IP": "IP адрес",
"JOINED": "Присоеденился",
"LANGUAGE": "Язык",
"LINK": "Ссылка",
"LEVEL": "Уровень",
"MONEY": "Деньги",
"MEMBER": "Участник",

View file

@ -3,5 +3,5 @@
"USAGE": "",
"EXAMPLES": "back",
"NO_PREV_SONG": "Предыдущий трек отсутствует",
"SUCCESS": "Играет предыдущий трек"
"SUCCESS": "Включён предыдущий трек"
}

View file

@ -3,6 +3,7 @@
"USAGE": "",
"EXAMPLES": "nowplaying",
"CURRENTLY_PLAYING": "Сейчас играет",
"LINK": "Введите ссылку в чат",
"T_TITLE": "Название",
"T_AUTHOR": "Автор",
"T_DURATION": "Длительность",

View file

@ -31,6 +31,7 @@
"IP": "IP-адреса",
"JOINED": "Приєднався",
"LANGUAGE": "Мова",
"LINK": "Силка",
"LEVEL": "Рівень",
"MONEY": "Гроші",
"MEMBER": "Учасник",

View file

@ -3,5 +3,5 @@
"USAGE": "",
"EXAMPLES": "back",
"NO_PREV_SONG": "Попередній трек відсутній",
"SUCCESS": "Грає попередній трек"
"SUCCESS": "Включений попередній трек"
}

View file

@ -3,6 +3,7 @@
"USAGE": "",
"EXAMPLES": "nowplaying",
"CURRENTLY_PLAYING": "Зараз грає",
"LINK": "Введіть силку на чат",
"T_TITLE": "Назва",
"T_AUTHOR": "Автор",
"T_DURATION": "Тривалість",

View file

@ -1,6 +1,6 @@
{
"name": "jaba",
"version": "4.3.6",
"version": "4.4.0",
"description": "My Discord Bot",
"main": "index.js",
"scripts": {
@ -8,7 +8,7 @@
"start": "node .",
"lint": "eslint . --ext .js"
},
"author": "Discord: jonny_bro",
"author": "Discord: @jonny_bro",
"dependencies": {
"@discord-player/extractor": "^4.4.5",
"@discordjs/opus": "^0.9.0",
@ -35,13 +35,13 @@
"eslint": "^8.52.0"
},
"eslintConfig": {
"extends": "eslint:recommended",
"env": {
"commonjs": true,
"es6": true,
"es2020": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"