Main music functionality done

This commit is contained in:
Jonny_Bro (Nikita) 2024-04-29 15:52:36 +05:00
parent b15aad7d6b
commit 43eff65314
No known key found for this signature in database
GPG key ID: 3F1ECC04147E9BD8
23 changed files with 190 additions and 242 deletions

View file

@ -1,41 +0,0 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Skip extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("skip")
.setDescription(client.translate("music/skip:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("music/skip:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/skip:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
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");
queue.node.skip();
interaction.success("music/skip:SUCCESS");
}
}
module.exports = Skip;

View file

@ -1,59 +0,0 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Skipto extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("skipto")
.setDescription(client.translate("music/skipto:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("music/skipto:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/skipto:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.addIntegerOption(option =>
option
.setName("position")
.setDescription(client.translate("music/skipto:POSITION"))
.setDescriptionLocalizations({
uk: client.translate("music/skipto:POSITION", null, "uk-UA"),
ru: client.translate("music/skipto:POSITION", null, "ru-RU"),
})
.setRequired(true),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
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 position = interaction.options.getInteger("position");
if (position <= 0) return interaction.error("music/skipto:NO_PREV_SONG");
if (queue.tracks.at(position - 1)) {
queue.node.skipTo(queue.tracks.at(position - 1));
interaction.success("music/skipto:SUCCESS", {
track: queue.tracks.at(0).title,
});
} else return interaction.error("music/skipto:ERROR", { position });
}
}
module.exports = Skipto;

View file

@ -153,13 +153,14 @@ class Number extends BaseCommand {
client.on("interactionCreate", async interaction => {
if (!interaction.isButton()) return;
await interaction.deferUpdate();
if (interaction.customId.startsWith("number_")) {
await interaction.deferUpdate();
if (interaction.customId === "number_delete_yes")
interaction.channel.delete();
else if (interaction.customId === "number_delete_no") {
await interaction.message.delete();
interaction.channel.setArchived(true);
if (interaction.customId === "number_delete_yes") interaction.channel.delete();
else if (interaction.customId === "number_delete_no") {
await interaction.message.delete();
interaction.channel.setArchived(true);
}
}
});
}

View file

@ -1,5 +1,4 @@
const { SlashCommandBuilder } = require("discord.js"),
{ QueueRepeatMode } = require("discord-player");
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Loop extends BaseCommand {
@ -27,10 +26,10 @@ class Loop extends BaseCommand {
})
.setRequired(true)
.setChoices(
{ name: client.translate("music/loop:AUTOPLAY"), value: "3" },
{ name: client.translate("music/loop:QUEUE"), value: "2" },
{ name: client.translate("music/loop:TRACK"), value: "1" },
{ name: client.translate("music/loop:DISABLE"), value: "0" },
// { name: client.translate("music/loop:AUTOPLAY"), value: "3" },
{ name: client.translate("music/loop:QUEUE"), value: "queue" },
{ name: client.translate("music/loop:TRACK"), value: "track" },
{ name: client.translate("music/loop:DISABLE"), value: "off" },
),
),
dirname: __dirname,
@ -44,25 +43,25 @@ class Loop extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
await interaction.deferReply();
const voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING", null, { edit: true });
const type = interaction.options.getString("option");
const translated = {
"3": interaction.translate("music/loop:AUTOPLAY_ENABLED"),
"2": interaction.translate("music/loop:QUEUE_ENABLED"),
"1": interaction.translate("music/loop:TRACK_ENABLED"),
"0": interaction.translate("music/loop:LOOP_DISABLED"),
// "3": interaction.translate("music/loop:AUTOPLAY_ENABLED"),
"queue": interaction.translate("music/loop:QUEUE_ENABLED"),
"track": interaction.translate("music/loop:TRACK_ENABLED"),
"off": interaction.translate("music/loop:LOOP_DISABLED"),
};
const type = interaction.options.getString("option"),
mode = type === "3" ? QueueRepeatMode.AUTOPLAY : type === "2" ? QueueRepeatMode.QUEUE : type === "1" ? QueueRepeatMode.TRACK : QueueRepeatMode.OFF;
queue.setRepeatMode(mode);
interaction.reply({ content: translated[type] });
await player.setRepeatMode(type);
interaction.editReply({ content: translated[type] });
}
}

View file

@ -29,42 +29,37 @@ class PlayContext extends BaseCommand {
if (!links) return interaction.error("music/play:NO_LINK", null, { edit: true });
const query = links[0],
voice = interaction.member.voice.channel;
voice = interaction.member.voice;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { edit: true });
const perms = voice.permissionsFor(client.user);
const perms = voice.channel.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,
const player = await client.lavalink.createPlayer({
guildId: interaction.guildId,
voiceChannelId: voice.channelId,
textChannelId: interaction.channelId,
selfDeaf: true,
selfMute: false,
volume: 100,
});
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: interaction,
},
selfDeaf: true,
leaveOnEnd: false,
leaveOnStop: true,
skipOnNoStream: true,
maxSize: 200,
maxHistorySize: 50,
});
await player.connect();
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: searchResult.hasPlaylist() ? searchResult.playlist.title : searchResult.tracks[0].title,
}),
});
const res = await player.search({ query }, interaction.member);
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];
if (res.loadType === "playlist") await player.queue.add(res.tracks);
else if (res.loadType === "search") await player.queue.add(res.tracks[0]);
else if (res.loadType === "track") await player.queue.add(res.tracks[0]);
else console.log(res);
queue.node.seek(time * 1000);
}
}
if (!player.playing) await player.play();
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
songName: res.loadType === "playlist" ? res.playlist.name : `${res.tracks[0].info.title} - ${res.tracks[0].info.author}`,
}),
});
}
}

View file

@ -59,14 +59,16 @@ class Play extends BaseCommand {
const res = await player.search({ query }, interaction.member);
await player.queue.add(res.tracks[0]);
if (res.loadType === "playlist") await player.queue.add(res.tracks);
else if (res.loadType === "search") await player.queue.add(res.tracks[0]);
else if (res.loadType === "track") await player.queue.add(res.tracks[0]);
else console.log(res);
if (!player.playing) await player.play();
interaction.editReply({
content: interaction.translate("music/play:ADDED_QUEUE", {
// songName: searchResult.hasPlaylist() ? searchResult.playlist.title : `${searchResult.tracks[0].title} - ${searchResult.tracks[0].author}`,
songName: res.tracks[0].info.title,
songName: res.loadType === "playlist" ? res.playlist.name : `${res.tracks[0].info.title} - ${res.tracks[0].info.author}`,
}),
});
}

View file

@ -31,12 +31,12 @@ class Queue extends BaseCommand {
if (interaction.customId.startsWith("queue_")) {
interaction.data = [];
interaction.data.guld = await client.findOrCreateGuild(interaction.guildId);
interaction.data.guild = await client.findOrCreateGuild(interaction.guildId);
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING");
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING");
const { embeds, size } = generateQueueEmbeds(interaction, queue);
const { embeds, size } = generateQueueEmbeds(interaction, player);
let currentPage = Number(interaction.message.content.match(/\d+/g)[0]) - 1 ?? 0;
@ -124,10 +124,10 @@ class Queue extends BaseCommand {
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING");
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING");
const { embeds, size } = generateQueueEmbeds(interaction, queue),
const { embeds, size } = generateQueueEmbeds(interaction, player),
row = new ActionRowBuilder().addComponents(
new ButtonBuilder().setCustomId("queue_prev_page").setStyle(ButtonStyle.Primary).setEmoji("⬅️"),
new ButtonBuilder().setCustomId("queue_next_page").setStyle(ButtonStyle.Primary).setEmoji("➡️"),
@ -152,28 +152,28 @@ class Queue extends BaseCommand {
/**
*
* @param {import("discord.js").ChatInputCommandInteraction} interaction
* @param {import("discord-player").GuildQueue} queue
* @param {import("lavalink-client").Player} player
* @returns
*/
function generateQueueEmbeds(interaction, queue) {
function generateQueueEmbeds(interaction, player) {
const embeds = [],
currentTrack = queue.currentTrack,
currentTrack = player.queue.current,
translated = {
"3": interaction.translate("music/loop:AUTOPLAY"),
"2": interaction.translate("music/loop:QUEUE"),
"1": interaction.translate("music/loop:TRACK"),
"0": interaction.translate("common:DISABLED"),
// "3": interaction.translate("music/loop:AUTOPLAY"),
"queue": interaction.translate("music/loop:QUEUE"),
"track": interaction.translate("music/loop:TRACK"),
"off": interaction.translate("common:DISABLED"),
};
let k = 10;
if (!queue.tracks.size) {
if (!player.queue.tracks.length) {
const embed = interaction.client.embed({
title: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"),
thumbnail: currentTrack.thumbnail || null,
description: `${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")}`,
thumbnail: currentTrack.info.artworkUrl || null,
description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[player.repeatMode]}\`\n${
currentTrack.info.uri.startsWith("./clips") ? `${currentTrack.info.title} (clips)` : `[${currentTrack.info.title}](${currentTrack.info.uri})`
}\n> ${interaction.translate("music/queue:ADDED")} ${currentTrack.requester.toString()}\n\n**${interaction.translate("music/queue:NEXT")}**\n${interaction.translate("music/queue:NO_QUEUE")}`,
});
embeds.push(embed);
@ -181,19 +181,19 @@ function generateQueueEmbeds(interaction, queue) {
return { embeds: embeds, size: embeds.length };
}
for (let i = 0; i < queue.getSize(); i += 10) {
const current = queue.tracks.toArray().slice(i, k);
for (let i = 0; i < player.queue.tracks.length; i += 10) {
const current = player.queue.tracks.slice(i, k);
let j = i;
k += 10;
const info = current.map(track => `${++j}. ${track.url.startsWith("./clips") ? `${track.title} (clips)` : `[${track.title}](${track.url})`}\n> ${interaction.translate("music/queue:ADDED")} ${track.requestedBy}`).join("\n");
const info = current.map(track => `${++j}. ${track.info.uri.startsWith("./clips") ? `${track.info.title} (clips)` : `[${track.info.title}](${track.info.uri})`}\n> ${interaction.translate("music/queue:ADDED")} ${track.requester.toString()}`).join("\n");
const embed = interaction.client.embed({
title: interaction.translate("music/nowplaying:CURRENTLY_PLAYING"),
thumbnail: currentTrack.thumbnail || null,
description: `${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}`,
thumbnail: currentTrack.info.artworkUrl || null,
description: `${interaction.translate("music/nowplaying:REPEAT")}: \`${translated[player.repeatMode]}\`\n${
currentTrack.info.uri.startsWith("./clips") ? `${currentTrack.info.title} (clips)` : `[${currentTrack.info.title}](${currentTrack.info.uri})`
}\n * ${interaction.translate("music/queue:ADDED")} ${currentTrack.requester.toString()}\n\n**${interaction.translate("music/queue:NEXT")}**\n${info}`,
});
embeds.push(embed);

View file

@ -40,10 +40,11 @@ class Seek extends BaseCommand {
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 player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING");
await player.seek(time * 1000);
queue.node.seek(time * 1000);
interaction.success("music/seek:SUCCESS", {
time: `**${time}** ${client.functions.getNoun(time, interaction.translate("misc:NOUNS:SECONDS:1"), interaction.translate("misc:NOUNS:SECONDS:2"), interaction.translate("misc:NOUNS:SECONDS:5"))}`,
});

View file

@ -30,10 +30,10 @@ class Shuffle extends BaseCommand {
const voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { ephemeral: true });
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true });
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true });
queue.tracks.shuffle();
await player.queue.shuffle();
interaction.success("music/shuffle:SUCCESS");
}
}

66
commands/Music/skip.js Normal file
View file

@ -0,0 +1,66 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
class Skip extends BaseCommand {
/**
*
* @param {import("../base/Client")} client
*/
constructor(client) {
super({
command: new SlashCommandBuilder()
.setName("skip")
.setDescription(client.translate("music/skip:DESCRIPTION"))
.setDescriptionLocalizations({
uk: client.translate("music/skip:DESCRIPTION", null, "uk-UA"),
ru: client.translate("music/skip:DESCRIPTION", null, "ru-RU"),
})
.setDMPermission(false)
.addIntegerOption(option =>
option
.setName("position")
.setDescription(client.translate("music/skip:POSITION"))
.setDescriptionLocalizations({
uk: client.translate("music/skip:POSITION", null, "uk-UA"),
ru: client.translate("music/skip:POSITION", null, "ru-RU"),
})
.setRequired(false),
),
dirname: __dirname,
ownerOnly: false,
});
}
/**
*
* @param {import("../../base/Client")} client
* @param {import("discord.js").ChatInputCommandInteraction} interaction
*/
async execute(client, interaction) {
const voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL");
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING");
const position = interaction.options.getInteger("position");
if (position) {
if (position <= 0) return interaction.error("music/skip:NO_PREV_SONG");
if (player.queue.tracks[position]) {
await player.skip(position);
return interaction.success("music/skip:SUCCESS", {
track: player.queue.current.info.title,
});
} else return interaction.error("music/skip:ERROR", { position });
} else {
await player.skip();
interaction.success("music/skip:SUCCESS");
}
}
}
module.exports = Skip;

View file

@ -30,10 +30,10 @@ class Stop extends BaseCommand {
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 player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING");
queue.delete();
await player.destroy();
interaction.success("music/stop:SUCCESS");
}
}

View file

@ -1,5 +1,6 @@
const { SlashCommandBuilder } = require("discord.js");
const BaseCommand = require("../../base/BaseCommand");
const numbers = Array.from({ length: 100 }, (_, k) => k + 1);
class Volume extends BaseCommand {
/**
@ -41,13 +42,13 @@ class Volume extends BaseCommand {
const voice = interaction.member.voice.channel;
if (!voice) return interaction.error("music/play:NO_VOICE_CHANNEL", null, { ephemeral: true });
const queue = client.player.nodes.get(interaction.guildId);
if (!queue) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true });
const player = client.lavalink.getPlayer(interaction.guildId);
if (!player) return interaction.error("music/play:NOT_PLAYING", null, { ephemeral: true });
const volume = interaction.options.getInteger("int");
if (volume <= 0 || volume > 100) return interaction.error("misc:INVALID_NUMBER_RANGE", { min: 1, max: 100 });
queue.node.setVolume(volume);
await player.setVolume(volume);
interaction.success("music/volume:SUCCESS", {
volume,
});
@ -61,7 +62,7 @@ class Volume extends BaseCommand {
*/
async autocompleteRun(client, interaction) {
const int = interaction.options.getInteger("int"),
results = Array.from({ length: 100 }, (_, k) => k + 1).filter(i => i.toString().includes(int));
results = numbers.filter(i => i.toString().includes(int));
return await interaction.respond(
results.slice(0, 25).map(i => ({

View file

@ -29,9 +29,6 @@ class Ready extends BaseEvent {
const checkReminds = require("../helpers/checkReminds");
checkReminds.init(client);
await client.lavalink.init({ ...client.user });
client.on("raw", d => client.lavalink.sendRawData(d));
if (client.config.dashboard.enabled) await client.dashboard.load(client);
client.logger.ready(`Loaded a total of ${commands.length} command(s).`);
@ -64,6 +61,10 @@ class Ready extends BaseEvent {
if (status[i + 1]) i++;
else i = 0;
}, 30 * 1000); // Every 30 seconds
await client.lavalink.init({ ...client.user });
client.on("raw", d => client.lavalink.sendRawData(d));
client.logger.ready("Lavalink ready.");
}
}

View file

@ -5,7 +5,7 @@ User.prototype.getUsername = function () {
};
BaseInteraction.prototype.getLocale = function () {
return this.guild ? this.data?.guild?.language : "en-US";
return this.data?.guild?.language ?? "en-US";
};
BaseInteraction.prototype.translate = function (key, args) {
@ -36,7 +36,7 @@ BaseInteraction.prototype.error = async function (key, args, options = {}) {
};
Message.prototype.getLocale = function () {
return this.guild ? this.data?.guild?.language : "en-US";
return this.data?.guild?.language ?? "en-US";
};
Message.prototype.translate = function (key, args) {

View file

@ -21,8 +21,8 @@ const client = new Client({
client
.on("disconnect", () => client.logger.warn("Bot is disconnecting..."))
.on("reconnecting", () => client.logger.warn("Bot reconnecting..."))
.on("warn", warn => client.logger.warn(warn))
.on("error", e => client.logger.error(`${e.message}\n${e.stack}`));
.on("warn", warn => console.log(warn))
.on("error", e => console.log(e));
process
.on("unhandledRejection", e => console.log(e))

View file

@ -1,7 +1,7 @@
{
"DESCRIPTION": "Rewinds the current track to the specified position",
"DESCRIPTION": "Seeks the current track to the specified time",
"USAGE": "[time]",
"EXAMPLES": "seek time:60",
"TIME": "Time in seconds",
"SUCCESS": "Track rewinded to {{time}}"
"SUCCESS": "Seeked to {{time}}"
}

View file

@ -1,6 +1,9 @@
{
"DESCRIPTION": "Skips the current track",
"USAGE": "",
"EXAMPLES": "skip",
"SUCCESS": "Track skipped"
"DESCRIPTION": "Jumps to a specified track",
"USAGE": "[position]",
"EXAMPLES": "skipto position:3",
"POSITION": "Track number in the queue",
"SUCCESS": "Jumped to track **{{track}}**",
"ERROR": "Nothing found at position {{position}}",
"NO_PREV_SONG": "You cannot go back, use the `back` command for that"
}

View file

@ -1,9 +0,0 @@
{
"DESCRIPTION": "Jumps to a specified track",
"USAGE": "[position]",
"EXAMPLES": "skipto position:3",
"POSITION": "Track number in the queue",
"SUCCESS": "Jumped to track **{{track}}**",
"ERROR": "Nothing found at position {{position}}",
"NO_PREV_SONG": "You cannot go back, use the `back` command for that"
}

View file

@ -1,6 +1,9 @@
{
"DESCRIPTION": "Пропустить текущий трек",
"USAGE": "",
"EXAMPLES": "skip",
"SUCCESS": "Трек пропущен"
"DESCRIPTION": "Пропустить текущий трек или перейти на заданный",
"USAGE": "(position)",
"EXAMPLES": "skip position:3",
"POSITION": "Номер трека в очереди",
"SUCCESS": "Выполнен переход на трек **{{track}}**",
"ERROR": "На позиции {{position}} ничего не найдено",
"NO_PREV_SONG": "Вы не можете перейти назад, для этого используйте команду `back`"
}

View file

@ -1,9 +0,0 @@
{
"DESCRIPTION": "Перейти на заданный трек",
"USAGE": "[position]",
"EXAMPLES": "skipto position:3",
"POSITION": "Номер трека в очереди",
"SUCCESS": "Выполнен переход на трек **{{track}}**",
"ERROR": "На позиции {{position}} ничего не найдено",
"NO_PREV_SONG": "Вы не можете перейти назад, для этого используйте команду `back`"
}

View file

@ -1,6 +1,9 @@
{
"DESCRIPTION": "Пропустити поточний трек",
"USAGE": "",
"EXAMPLES": "skip",
"SUCCESS": "Трек пропущено"
"DESCRIPTION": "Перейти на заданий трек",
"USAGE": "[position]",
"EXAMPLES": "skipto position:3",
"POSITION": "Номер треку в черзі",
"SUCCESS": "Перехід на трек **{{track}}**",
"ERROR": "На позиції {{position}} нічого не знайдено",
"NO_PREV_SONG": "Ви не можете перейти назад, для цього використовуйте команду `back`"
}

View file

@ -1,9 +0,0 @@
{
"DESCRIPTION": "Перейти на заданий трек",
"USAGE": "[position]",
"EXAMPLES": "skipto position:3",
"POSITION": "Номер треку в черзі",
"SUCCESS": "Перехід на трек **{{track}}**",
"ERROR": "На позиції {{position}} нічого не знайдено",
"NO_PREV_SONG": "Ви не можете перейти назад, для цього використовуйте команду `back`"
}

View file

@ -8,7 +8,7 @@
"start": "node .",
"lint": "eslint . --ext .js --ignore-pattern \"dashboard-core/\""
},
"author": "Discord: @jonny_bro",
"author": "@jonny_bro",
"dependencies": {
"@discordjs/opus": "^0.9.0",
"@discordjs/rest": "^2.2.0",