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.extractors.loadDefault();
this.player.events.on("playerStart", async (queue, track) => { 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) if (track.durationMS > 1)
setTimeout(() => { setTimeout(() => {
if (m.deletable) m.delete(); const message = queue.metadata.channel.messages.cache.get(m);
if (message.deletable) message.delete();
}, track.durationMS); }, track.durationMS);
else else
setTimeout(() => { 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 }, 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))); 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 * @param {String} locale Language
*/ */
translate(key, args, locale = this.defaultLanguage) { translate(key, args, locale = this.defaultLanguage) {
const language = this.translations.get(locale); const lang = this.translations.get(locale);
if (!language) throw "Invalid language set in data.";
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", { content: interaction.translate("owner/debug:SUCCESS_LEVEL", {
user: interaction.member.toString(), user: interaction.member.toString(),
amount: level, 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({ await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"),
components: [row], components: [row],
}); });
} }

View file

@ -207,7 +207,7 @@ async function changeSetting(interaction, setting, state, channel, guildData) {
await guildData.save(); await guildData.save();
return interaction.reply({ 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, ephemeral: true,
}); });
} else { } else {
@ -226,7 +226,7 @@ async function changeSetting(interaction, setting, state, channel, guildData) {
} else } else
return interaction.reply({ return interaction.reply({
content: `${interaction.translate(`administration/config:${settingSplitted.length === 2 ? settingSplitted[1].toUpperCase() : setting.toUpperCase()}`)}: ${ 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, ephemeral: true,
}); });

View file

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

View file

@ -167,18 +167,16 @@ class Marry extends BaseCommand {
content: interaction.translate("economy/marry:SUCCESS", { content: interaction.translate("economy/marry:SUCCESS", {
creator: interaction.member.toString(), creator: interaction.member.toString(),
partner: member.toString(), partner: member.toString(),
}), }, "success"),
components: [], components: [],
}); });
} else { } else return interaction.editReply({
return interaction.editReply({ content: interaction.translate("economy/marry:DENIED", {
content: interaction.translate("economy/marry:DENIED", { creator: interaction.member.toString(),
creator: interaction.member.toString(), partner: member.toString(),
partner: member.toString(), }, "error"),
}), components: [],
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 => { client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return; if (!interaction.isButton()) return;
if (interaction.customId.includes("boosters_")) { if (interaction.customId.startsWith("boosters_")) {
const guildData = client.findOrCreateGuild(interaction.guildId), const guildData = client.findOrCreateGuild(interaction.guildId),
boosters = (await interaction.guild.members.fetch()).filter(m => m.premiumSince), boosters = (await interaction.guild.members.fetch()).filter(m => m.premiumSince),
embeds = generateBoostersEmbeds(client, interaction, boosters, guildData); embeds = generateBoostersEmbeds(client, interaction, boosters, guildData);
@ -41,7 +41,7 @@ class Boosters extends BaseCommand {
new ButtonBuilder().setCustomId("boosters_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"), 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") { if (interaction.customId === "boosters_prev_page") {
await interaction.deferUpdate(); 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({ await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"),
fetchReply: true, fetchReply: true,
components: [row], components: [row],
}); });

View file

@ -1,14 +1,18 @@
const { ContextMenuCommandBuilder, ModalBuilder, EmbedBuilder, ActionRowBuilder, TextInputBuilder, ApplicationCommandType, PermissionsBitField, TextInputStyle } = require("discord.js"); const { ContextMenuCommandBuilder, ModalBuilder, EmbedBuilder, ActionRowBuilder, TextInputBuilder, ApplicationCommandType, PermissionsBitField, TextInputStyle } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand"); const BaseCommand = require("../../base/BaseCommand");
class Warn extends BaseCommand { class WarnContext extends BaseCommand {
/** /**
* *
* @param {import("../../base/JaBa")} client * @param {import("../../base/JaBa")} client
*/ */
constructor() { constructor() {
super({ 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: [], aliases: [],
dirname: __dirname, dirname: __dirname,
ownerOnly: false, 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); const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true }); 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"), 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); 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"); { QueueRepeatMode } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand"); const BaseCommand = require("../../base/BaseCommand");
@ -26,8 +26,156 @@ class Nowplaying extends BaseCommand {
* *
* @param {import("../../base/JaBa")} client * @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,66 +183,92 @@ class Nowplaying extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction * @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {Object} data * @param {Object} data
*/ */
async execute(client, interaction, data) { async execute(client, interaction) {
await interaction.deferReply(); await interaction.deferReply();
const queue = client.player.nodes.get(interaction.guildId); const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true }); if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
const progressBar = queue.node.createProgressBar(),
track = queue.currentTrack;
const embed = new EmbedBuilder() const row1 = new ActionRowBuilder().addComponents(
.setAuthor({ new ButtonBuilder().setCustomId("nowp_prev_track").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
name: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"), new ButtonBuilder().setCustomId("nowp_loop").setStyle(ButtonStyle.Secondary).setEmoji("🔁"),
}) new ButtonBuilder().setCustomId("nowp_add_track").setStyle(ButtonStyle.Success).setEmoji("▶️"),
.setThumbnail(track.thumbnail) new ButtonBuilder().setCustomId("nowp_next_track").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
.addFields([ );
{
name: interaction.translate("music/nowplaying:T_TITLE"), const row2 = new ActionRowBuilder().addComponents(
value: `[${track.title}](${track.url})`, new ButtonBuilder().setCustomId("nowp_queue").setStyle(ButtonStyle.Secondary).setEmoji(""),
inline: true, new ButtonBuilder().setCustomId("nowp_stop").setStyle(ButtonStyle.Danger).setEmoji("⏹️"),
}, );
{
name: interaction.translate("music/nowplaying:T_AUTHOR"), const embed = await updateEmbed(interaction, queue);
value: track.author || interaction.translate("common:UNKNOWN"),
inline: true,
},
{ 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),
inline: true,
},
{
name: interaction.translate("music/queue:ADDED"),
value: track.requestedBy.toString(),
inline: true,
},
{
name: interaction.translate("music/nowplaying:T_DURATION"),
value: progressBar,
},
{
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")
}\``,
},
])
.setColor(client.config.embed.color)
.setFooter(client.config.embed.footer)
.setTimestamp();
interaction.editReply({ interaction.editReply({
embeds: [embed], 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,
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({
name: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"),
})
.setThumbnail(track.thumbnail)
.addFields([
{
name: interaction.translate("music/nowplaying:T_TITLE"),
value: `[${track.title}](${track.url})`,
inline: true,
},
{
name: interaction.translate("music/nowplaying:T_AUTHOR"),
value: track.author || interaction.translate("common:UNKNOWN"),
inline: true,
},
{ name: "\u200B", value: "\u200B", inline: true },
{
name: interaction.translate("common: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,
},
{
name: interaction.translate("music/queue:ADDED"),
value: track.requestedBy.toString(),
inline: true,
},
{
name: interaction.translate("music/nowplaying:T_DURATION"),
value: progressBar,
},
{
name: "\u200b",
value: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\``,
},
])
.setColor(interaction.client.config.embed.color)
.setFooter(interaction.client.config.embed.footer)
.setTimestamp();
return embed;
}
module.exports = Nowplaying; 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({ interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", { content: interaction.translate("music/play:ADDED_QUEUE", {
songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title, 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]; const time = query.match(/&t=[[0-9]+/g)[0].split("=")[1];
queue.node.seek(time * 1000); queue.node.seek(time * 1000);
} }
} }
} }
/** /**
@ -100,8 +100,9 @@ class Play extends BaseCommand {
*/ */
async autocompleteRun(client, interaction) { async autocompleteRun(client, interaction) {
const query = interaction.options.getString("query"); const query = interaction.options.getString("query");
if (query === "") return; if (query === "") return;
if (query.includes("http")) return interaction.respond([ if (query.startsWith("http")) return interaction.respond([
{ {
name: "Current link", name: "Current link",
value: query, value: query,

View file

@ -1,5 +1,4 @@
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require("discord.js"), const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ButtonBuilder, ButtonStyle } = require("discord.js");
{ QueueRepeatMode } = require("discord-player");
const BaseCommand = require("../../base/BaseCommand"); const BaseCommand = require("../../base/BaseCommand");
class Queue extends BaseCommand { class Queue extends BaseCommand {
@ -26,8 +25,94 @@ class Queue extends BaseCommand {
* *
* @param {import("../../base/JaBa")} client * @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,98 +124,24 @@ class Queue extends BaseCommand {
const queue = client.player.nodes.get(interaction.guildId); const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING"); if (!queue) return interaction.error("music/play:NOT_PLAYING");
let currentPage = 0; const { embeds, size } = generateQueueEmbeds(client, interaction, queue),
let embeds = 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("⏹️"),
);
const row = new ActionRowBuilder().addComponents( if (interaction.customId) return await interaction.followUp({
new ButtonBuilder().setCustomId("queue_prev_page").setLabel(interaction.translate("music/queue:PREV_PAGE")).setStyle(ButtonStyle.Primary).setEmoji("⬅️"), content: `${interaction.translate("common:PAGE")}: **1**/**${size}**`,
new ButtonBuilder().setCustomId("queue_next_page").setLabel(interaction.translate("music/queue:NEXT_PAGE")).setStyle(ButtonStyle.Primary).setEmoji("➡️"), embeds: [embeds[0]],
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("⏹️"),
);
await interaction.reply({
content: `${interaction.translate("common:PAGE")}: **${currentPage + 1}**/**${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row], components: [row],
}); });
const filter = i => i.user.id === interaction.user.id; await interaction.reply({
const collector = interaction.channel.createMessageComponentCollector({ filter, idle: 20 * 1000 }); content: `${interaction.translate("common:PAGE")}: **1**/**${size}**`,
embeds: [embeds[0]],
collector.on("collect", async i => { components: [row],
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) { function generateQueueEmbeds(client, interaction, queue) {
const embeds = [], 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; let k = 10;
@ -154,22 +172,14 @@ function generateQueueEmbeds(client, interaction, queue) {
.setThumbnail(currentTrack.thumbnail) .setThumbnail(currentTrack.thumbnail)
.setColor(interaction.client.config.embed.color) .setColor(interaction.client.config.embed.color)
.setDescription( .setDescription(
`${interaction.translate("music/nowplaying:REPEAT")}: \`${ `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${
queue.repeatMode === QueueRepeatMode.AUTOPLAY currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`
? interaction.translate("music/nowplaying:AUTOPLAY") }\n> ${interaction.translate("music/queue:ADDED")} ${currentTrack.requestedBy}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`,
: 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")}`,
) )
.setTimestamp(); .setTimestamp();
embeds.push(embed); embeds.push(embed);
return embeds; return { embeds: embeds, size: embeds.length };
} }
for (let i = 0; i < queue.getSize(); i += 10) { for (let i = 0; i < queue.getSize(); i += 10) {
@ -184,15 +194,9 @@ function generateQueueEmbeds(client, interaction, queue) {
.setThumbnail(currentTrack.thumbnail) .setThumbnail(currentTrack.thumbnail)
.setColor(interaction.client.config.embed.color) .setColor(interaction.client.config.embed.color)
.setDescription( .setDescription(
`${interaction.translate("music/nowplaying:REPEAT")}: \`${ `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[queue.repeatMode]}\`\n${
queue.repeatMode === QueueRepeatMode.AUTOPLAY currentTrack.url.startsWith("./clips") ? `${currentTrack.title} (clips)` : `[${currentTrack.title}](${currentTrack.url})`
? interaction.translate("music/nowplaying:AUTOPLAY") }\n * ${interaction.translate("music/queue:ADDED")} ${
: 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 currentTrack.requestedBy
}\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`, }\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`,
) )
@ -201,7 +205,7 @@ function generateQueueEmbeds(client, interaction, queue) {
embeds.push(embed); embeds.push(embed);
} }
return embeds; return { embeds: embeds, size: embeds.length };
} }
module.exports = Queue; 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({ await interaction.editReply({
content: interaction.translate("common:AVAILABLE_OPTIONS"), 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 button = new ButtonBuilder().setCustomId("cancel_closing").setLabel(interaction.translate("common:CANCEL")).setStyle(ButtonStyle.Danger);
const row = new ActionRowBuilder().addComponents(button); const row = new ActionRowBuilder().addComponents(button);
await interaction.reply({ await interaction.editReply({
embeds: [embed], embeds: [embed],
components: [row], components: [row],
}); });

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

View file

@ -17,11 +17,11 @@ const locales = {
module.exports.load = async client => { module.exports.load = async client => {
const commands = client.commands.map(v => { const commands = client.commands.map(v => {
return { return {
_category: v.category,
commandName: v.command.name, commandName: v.command.name,
commandDescription: client.translate(`${v.category.toLowerCase()}/${v.command.name}:DESCRIPTION`), commandDescription: client.translate(`${v.category.toLowerCase()}/${v.command.name}:DESCRIPTION`),
commandUsage: client.translate(`${v.category.toLowerCase()}/${v.command.name}:USAGE`), commandUsage: client.translate(`${v.category.toLowerCase()}/${v.command.name}:USAGE`),
commandAlias: "", commandAlias: "",
_category: v.category,
}; };
}); });
let categories = []; let categories = [];
@ -48,11 +48,6 @@ module.exports.load = async client => {
id: client.config.userId, id: client.config.userId,
secret: client.config.dashboard.secret, 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, cookiesSecret: client.config.dashboard.secret,
domain: client.config.dashboard.domain, domain: client.config.dashboard.domain,
redirectUri: `${client.config.dashboard.domain}/discord/callback`, redirectUri: `${client.config.dashboard.domain}/discord/callback`,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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