Apollo Initial Files

This commit is contained in:
2024-10-26 20:33:18 +08:00
commit 2d302551f9
82 changed files with 10643 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
import { CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
import { i18n } from "../utils/i18n";
import { bot } from "../index";
export default {
data: new SlashCommandBuilder().setName("help").setDescription(i18n.__("help.description")),
async execute(interaction: CommandInteraction) {
let commands = bot.slashCommandsMap;
let helpEmbed = new EmbedBuilder()
.setTitle(i18n.__mf("help.embedTitle", { botname: interaction.client.user!.username }))
.setDescription(i18n.__("help.embedDescription"))
.setColor("#F8AA2A");
commands.forEach((cmd) => {
helpEmbed.addFields({
name: `**${cmd.data.name}**`,
value: `${cmd.data.description}`,
inline: true
});
});
helpEmbed.setTimestamp();
return interaction.reply({ embeds: [helpEmbed] }).catch(console.error);
}
};
+30
View File
@@ -0,0 +1,30 @@
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ChatInputCommandInteraction,
EmbedBuilder,
SlashCommandBuilder
} from "discord.js";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder().setName("invite").setDescription(i18n.__("invite.description")),
execute(interaction: ChatInputCommandInteraction) {
const inviteEmbed = new EmbedBuilder().setTitle(i18n.__mf("Invite me to your server!"));
// return interaction with embed and button to invite the bot
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setLabel(i18n.__mf("Invite"))
.setStyle(ButtonStyle.Link)
.setURL(
`https://discord.com/api/oauth2/authorize?client_id=${
interaction.client.user!.id
}&permissions=8&scope=bot%20applications.commands`
)
);
return interaction.reply({ embeds: [inviteEmbed], components: [actionRow] }).catch(console.error);
}
};
+25
View File
@@ -0,0 +1,25 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("loop").setDescription(i18n.__("loop.description")),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!queue)
return interaction.reply({ content: i18n.__("loop.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!guildMemer || !canModifyQueue(guildMemer)) return i18n.__("common.errorNotChannel");
queue.loop = !queue.loop;
const content = i18n.__mf("loop.result", { loop: queue.loop ? i18n.__("common.on") : i18n.__("common.off") });
safeReply(interaction, content);
}
};
+34
View File
@@ -0,0 +1,34 @@
import { ChatInputCommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
import { i18n } from "../utils/i18n";
// @ts-ignore
import lyricsFinder from "lyrics-finder";
import { bot } from "../index";
export default {
data: new SlashCommandBuilder().setName("lyrics").setDescription(i18n.__("lyrics.description")),
async execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
if (!queue || !queue.songs.length) return interaction.reply(i18n.__("lyrics.errorNotQueue")).catch(console.error);
await interaction.reply("⏳ Loading...").catch(console.error);
let lyrics = null;
const title = queue.songs[0].title;
try {
lyrics = await lyricsFinder(queue.songs[0].title, "");
if (!lyrics) lyrics = i18n.__mf("lyrics.lyricsNotFound", { title: title });
} catch (error) {
lyrics = i18n.__mf("lyrics.lyricsNotFound", { title: title });
}
let lyricsEmbed = new EmbedBuilder()
.setTitle(i18n.__mf("lyrics.embedTitle", { title: title }))
.setDescription(lyrics.length >= 4096 ? `${lyrics.substr(0, 4093)}...` : lyrics)
.setColor("#F8AA2A")
.setTimestamp();
return interaction.editReply({ content: "", embeds: [lyricsEmbed] }).catch(console.error);
}
};
+46
View File
@@ -0,0 +1,46 @@
import move from "array-move";
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
export default {
data: new SlashCommandBuilder()
.setName("move")
.setDescription(i18n.__("move.description"))
.addIntegerOption((option) =>
option.setName("movefrom").setDescription(i18n.__("move.args.movefrom")).setRequired(true)
)
.addIntegerOption((option) =>
option.setName("moveto").setDescription(i18n.__("move.args.moveto")).setRequired(true)
),
execute(interaction: ChatInputCommandInteraction) {
const movefromArg = interaction.options.getInteger("movefrom");
const movetoArg = interaction.options.getInteger("moveto");
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
const queue = bot.queues.get(interaction.guild!.id);
if (!queue) return interaction.reply(i18n.__("move.errorNotQueue")).catch(console.error);
if (!canModifyQueue(guildMemer!)) return;
if (!movefromArg || !movetoArg)
return interaction.reply({ content: i18n.__mf("move.usagesReply", { prefix: bot.prefix }), ephemeral: true });
if (isNaN(movefromArg) || movefromArg <= 1)
return interaction.reply({ content: i18n.__mf("move.usagesReply", { prefix: bot.prefix }), ephemeral: true });
let song = queue.songs[movefromArg - 1];
queue.songs = move(queue.songs, movefromArg - 1, movetoArg == 1 ? 1 : movetoArg - 1);
interaction.reply({
content: i18n.__mf("move.result", {
author: interaction.user.id,
title: song.title,
index: movetoArg == 1 ? 1 : movetoArg
})
});
}
};
+45
View File
@@ -0,0 +1,45 @@
import { ChatInputCommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
import { splitBar } from "string-progressbar";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder().setName("nowplaying").setDescription(i18n.__("nowplaying.description")),
cooldown: 10,
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
if (!queue || !queue.songs.length)
return interaction.reply({ content: i18n.__("nowplaying.errorNotQueue"), ephemeral: true }).catch(console.error);
const song = queue.songs[0];
const seek = queue.resource.playbackDuration / 1000;
const left = song.duration - seek;
let nowPlaying = new EmbedBuilder()
.setTitle(i18n.__("nowplaying.embedTitle"))
.setDescription(`${song.title}\n${song.url}`)
.setColor("#F8AA2A");
if (song.duration > 0) {
nowPlaying.addFields({
name: "\u200b",
value:
new Date(seek * 1000).toISOString().substr(11, 8) +
"[" +
splitBar(song.duration == 0 ? seek : song.duration, seek, 20)[0] +
"]" +
(song.duration == 0 ? " ◉ LIVE" : new Date(song.duration * 1000).toISOString().substr(11, 8)),
inline: false
});
nowPlaying.setFooter({
text: i18n.__mf("nowplaying.timeRemaining", {
time: new Date(left * 1000).toISOString().substr(11, 8)
})
});
}
return interaction.reply({ embeds: [nowPlaying] });
}
};
+25
View File
@@ -0,0 +1,25 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("pause").setDescription(i18n.__("pause.description")),
execute(interaction: ChatInputCommandInteraction) {
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
const queue = bot.queues.get(interaction.guild!.id);
if (!queue) return interaction.reply({ content: i18n.__("pause.errorNotQueue") }).catch(console.error);
if (!canModifyQueue(guildMemer!)) return i18n.__("common.errorNotChannel");
if (queue.player.pause()) {
const content = i18n.__mf("pause.result", { author: interaction.user.id });
safeReply(interaction, content);
return true;
}
}
};
+12
View File
@@ -0,0 +1,12 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder().setName("ping").setDescription(i18n.__("ping.description")),
cooldown: 10,
execute(interaction: ChatInputCommandInteraction) {
interaction
.reply({ content: i18n.__mf("ping.result", { ping: Math.round(interaction.client.ws.ping) }), ephemeral: true })
.catch(console.error);
}
};
+98
View File
@@ -0,0 +1,98 @@
import { DiscordGatewayAdapterCreator, joinVoiceChannel } from "@discordjs/voice";
import { ChatInputCommandInteraction, PermissionsBitField, SlashCommandBuilder, TextChannel } from "discord.js";
import { bot } from "../index";
import { MusicQueue } from "../structs/MusicQueue";
import { Song } from "../structs/Song";
import { i18n } from "../utils/i18n";
import { playlistPattern } from "../utils/patterns";
export default {
data: new SlashCommandBuilder()
.setName("play")
.setDescription(i18n.__("play.description"))
.addStringOption((option) => option.setName("song").setDescription("The song you want to play").setRequired(true)),
cooldown: 3,
permissions: [PermissionsBitField.Flags.Connect, PermissionsBitField.Flags.Speak],
async execute(interaction: ChatInputCommandInteraction, input: string) {
let argSongName = interaction.options.getString("song");
if (!argSongName) argSongName = input;
const guildMember = interaction.guild!.members.cache.get(interaction.user.id);
const { channel } = guildMember!.voice;
if (!channel)
return interaction.reply({ content: i18n.__("play.errorNotChannel"), ephemeral: true }).catch(console.error);
const queue = bot.queues.get(interaction.guild!.id);
if (queue && channel.id !== queue.connection.joinConfig.channelId)
return interaction
.reply({
content: i18n.__mf("play.errorNotInSameChannel", { user: bot.client.user!.username }),
ephemeral: true
})
.catch(console.error);
if (!argSongName)
return interaction
.reply({ content: i18n.__mf("play.usageReply", { prefix: bot.prefix }), ephemeral: true })
.catch(console.error);
const url = argSongName;
if (interaction.replied) await interaction.editReply("⏳ Loading...").catch(console.error);
else await interaction.reply("⏳ Loading...");
// Start the playlist if playlist url was provided
if (playlistPattern.test(url)) {
await interaction.editReply("🔗 Link is playlist").catch(console.error);
return bot.slashCommandsMap.get("playlist")!.execute(interaction, "song");
}
let song;
try {
song = await Song.from(url, url);
} catch (error: any) {
console.error(error);
if (error.name == "NoResults")
return interaction
.reply({ content: i18n.__mf("play.errorNoResults", { url: `<${url}>` }), ephemeral: true })
.catch(console.error);
if (error.name == "InvalidURL")
return interaction
.reply({ content: i18n.__mf("play.errorInvalidURL", { url: `<${url}>` }), ephemeral: true })
.catch(console.error);
if (interaction.replied)
return await interaction.editReply({ content: i18n.__("common.errorCommand") }).catch(console.error);
else return interaction.reply({ content: i18n.__("common.errorCommand"), ephemeral: true }).catch(console.error);
}
if (queue) {
queue.enqueue(song);
return (interaction.channel as TextChannel)
.send({ content: i18n.__mf("play.queueAdded", { title: song.title, author: interaction.user.id }) })
.catch(console.error);
}
const newQueue = new MusicQueue({
interaction,
textChannel: interaction.channel! as TextChannel,
connection: joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator
})
});
bot.queues.set(interaction.guild!.id, newQueue);
newQueue.enqueue(song);
interaction.deleteReply().catch(console.error);
}
};
+102
View File
@@ -0,0 +1,102 @@
import { DiscordGatewayAdapterCreator, joinVoiceChannel } from "@discordjs/voice";
import {
ChatInputCommandInteraction,
EmbedBuilder,
PermissionsBitField,
SlashCommandBuilder,
TextChannel
} from "discord.js";
import { bot } from "../index";
import { MusicQueue } from "../structs/MusicQueue";
import { Playlist } from "../structs/Playlist";
import { Song } from "../structs/Song";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder()
.setName("playlist")
.setDescription(i18n.__("playlist.description"))
.addStringOption((option) => option.setName("playlist").setDescription("Playlist name or link").setRequired(true)),
cooldown: 5,
permissions: [PermissionsBitField.Flags.Connect, PermissionsBitField.Flags.Speak],
async execute(interaction: ChatInputCommandInteraction, queryOptionName = "playlist") {
let argSongName = interaction.options.getString(queryOptionName);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
const { channel } = guildMemer!.voice;
const queue = bot.queues.get(interaction.guild!.id);
if (!channel)
return interaction.reply({ content: i18n.__("playlist.errorNotChannel"), ephemeral: true }).catch(console.error);
if (queue && channel.id !== queue.connection.joinConfig.channelId)
if (interaction.replied)
return interaction
.editReply({ content: i18n.__mf("play.errorNotInSameChannel", { user: interaction.client.user!.username }) })
.catch(console.error);
else
return interaction
.reply({
content: i18n.__mf("play.errorNotInSameChannel", { user: interaction.client.user!.username }),
ephemeral: true
})
.catch(console.error);
let playlist;
try {
playlist = await Playlist.from(argSongName!.split(" ")[0], argSongName!);
} catch (error) {
console.error(error);
if (interaction.replied)
return interaction.editReply({ content: i18n.__("playlist.errorNotFoundPlaylist") }).catch(console.error);
else
return interaction
.reply({ content: i18n.__("playlist.errorNotFoundPlaylist"), ephemeral: true })
.catch(console.error);
}
if (queue) {
queue.songs.push(...playlist.videos);
} else {
const newQueue = new MusicQueue({
interaction,
textChannel: interaction.channel! as TextChannel,
connection: joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator as DiscordGatewayAdapterCreator
})
});
bot.queues.set(interaction.guild!.id, newQueue);
newQueue.enqueue(...playlist.videos);
}
let playlistEmbed = new EmbedBuilder()
.setTitle(`${playlist.data.title}`)
.setDescription(
playlist.videos
.map((song: Song, index: number) => `${index + 1}. ${song.title}`)
.join("\n")
.slice(0, 4095)
)
.setURL(playlist.data.url!)
.setColor("#F8AA2A")
.setTimestamp();
if (interaction.replied)
return interaction.editReply({
content: i18n.__mf("playlist.startedPlaylist", { author: interaction.user.id }),
embeds: [playlistEmbed]
});
interaction
.reply({
content: i18n.__mf("playlist.startedPlaylist", { author: interaction.user.id }),
embeds: [playlistEmbed]
})
.catch(console.error);
}
};
+125
View File
@@ -0,0 +1,125 @@
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ChatInputCommandInteraction,
CommandInteraction,
EmbedBuilder,
Interaction,
SlashCommandBuilder
} from "discord.js";
import { bot } from "../index";
import { Song } from "../structs/Song";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder().setName("queue").setDescription(i18n.__("queue.description")),
cooldown: 5,
async execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
if (!queue || !queue.songs.length) return interaction.reply({ content: i18n.__("queue.errorNotQueue") });
let currentPage = 0;
const embeds = generateQueueEmbed(interaction, queue.songs);
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder().setCustomId("previous").setLabel("⬅️").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("stop").setLabel("⏹").setStyle(ButtonStyle.Secondary),
new ButtonBuilder().setCustomId("next").setLabel("➡️").setStyle(ButtonStyle.Secondary)
);
await interaction.reply("⏳ Loading queue...");
if (interaction.replied)
await interaction.editReply({
content: `**${i18n.__mf("queue.currentPage")} ${currentPage + 1}/${embeds.length}**`,
embeds: [embeds[currentPage]],
components: [row]
});
const queueEmbed = await interaction.fetchReply();
const filter = (buttonInteraction: Interaction) =>
buttonInteraction.isButton() && buttonInteraction.user.id === interaction.user.id;
const collector = queueEmbed.createMessageComponentCollector({ filter, time: 60000 });
const buttonHandlers = {
next: async () => {
if (currentPage >= embeds.length - 1) return;
currentPage++;
await interaction.editReply({
content: `**${i18n.__mf("queue.currentPage", {
page: currentPage + 1,
length: embeds.length
})}**`,
embeds: [embeds[currentPage]],
components: [row]
});
},
previous: async () => {
if (currentPage === 0) return;
currentPage--;
await interaction.editReply({
content: `**${i18n.__mf("queue.currentPage", {
page: currentPage + 1,
length: embeds.length
})}**`,
embeds: [embeds[currentPage]],
components: [row]
});
},
stop: async () => {
await interaction.editReply({
components: []
});
collector.stop();
}
};
collector.on("collect", async (buttonInteraction) => {
buttonInteraction.deferUpdate();
const handler = buttonHandlers[buttonInteraction.customId as keyof typeof buttonHandlers];
if (handler) {
await handler();
}
});
collector.on("end", () => {
queueEmbed
.edit({
components: []
})
.catch(console.error);
});
}
};
function generateQueueEmbed(interaction: CommandInteraction, songs: Song[]) {
let embeds = [];
let k = 10;
for (let i = 0; i < songs.length; i += 10) {
const current = songs.slice(i, k);
let j = i;
k += 10;
const info = current.map((track) => `${++j} - [${track.title}](${track.url})`).join("\n");
const embed = new EmbedBuilder()
.setTitle(i18n.__("queue.embedTitle"))
.setThumbnail(interaction.guild?.iconURL()!)
.setColor("#F8AA2A")
.setDescription(i18n.__mf("queue.embedCurrentSong", { title: songs[0].title, url: songs[0].url, info: info }))
.setTimestamp();
embeds.push(embed);
}
return embeds;
}
+57
View File
@@ -0,0 +1,57 @@
import { SlashCommandBuilder, CommandInteraction, ChatInputCommandInteraction } from "discord.js";
import { bot } from "../index";
import { Song } from "../structs/Song";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
const pattern = /^[0-9]{1,2}(\s*,\s*[0-9]{1,2})*$/;
export default {
data: new SlashCommandBuilder()
.setName("remove")
.setDescription(i18n.__("remove.description"))
.addStringOption((option) =>
option.setName("slot").setDescription(i18n.__("remove.description")).setRequired(true)
),
execute(interaction: ChatInputCommandInteraction) {
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
const removeArgs = interaction.options.getString("slot");
const queue = bot.queues.get(interaction.guild!.id);
if (!queue)
return interaction.reply({ content: i18n.__("remove.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!canModifyQueue(guildMemer!)) return i18n.__("common.errorNotChannel");
if (!removeArgs)
return interaction.reply({ content: i18n.__mf("remove.usageReply", { prefix: bot.prefix }), ephemeral: true });
const songs = removeArgs.split(",").map((arg) => parseInt(arg));
let removed: Song[] = [];
if (pattern.test(removeArgs)) {
queue.songs = queue.songs.filter((item, index) => {
if (songs.find((songIndex) => songIndex - 1 === index)) removed.push(item);
else return true;
});
interaction.reply(
i18n.__mf("remove.result", {
title: removed.map((song) => song.title).join("\n"),
author: interaction.user.id
})
);
} else if (!isNaN(+removeArgs) && +removeArgs >= 1 && +removeArgs <= queue.songs.length) {
return interaction.reply(
i18n.__mf("remove.result", {
title: queue.songs.splice(+removeArgs - 1, 1)[0].title,
author: interaction.user.id
})
);
} else {
return interaction.reply({ content: i18n.__mf("remove.usageReply", { prefix: bot.prefix }) });
}
}
};
+32
View File
@@ -0,0 +1,32 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("resume").setDescription(i18n.__("resume.description")),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!queue)
return interaction.reply({ content: i18n.__("resume.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!canModifyQueue(guildMemer!)) return i18n.__("common.errorNotChannel");
if (queue.player.unpause()) {
const content = i18n.__mf("resume.resultNotPlaying", { author: interaction.user.id });
safeReply(interaction, content);
return true;
}
const content = i18n.__("resume.errorPlaying");
safeReply(interaction, content);
return false;
}
};
+86
View File
@@ -0,0 +1,86 @@
import {
ActionRowBuilder,
ChatInputCommandInteraction,
SlashCommandBuilder,
StringSelectMenuBuilder,
StringSelectMenuInteraction
} from "discord.js";
import youtube, { Video } from "youtube-sr";
import { bot } from "..";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder()
.setName("search")
.setDescription(i18n.__("search.description"))
.addStringOption((option) =>
option.setName("query").setDescription(i18n.__("search.optionQuery")).setRequired(true)
),
async execute(interaction: ChatInputCommandInteraction) {
const query = interaction.options.getString("query", true);
const member = interaction.guild!.members.cache.get(interaction.user.id);
if (!member?.voice.channel)
return interaction.reply({ content: i18n.__("search.errorNotChannel"), ephemeral: true }).catch(console.error);
const search = query;
await interaction.reply("⏳ Loading...").catch(console.error);
let results: Video[] = [];
try {
results = await youtube.search(search, { limit: 10, type: "video" });
} catch (error) {
console.error(error);
interaction.editReply({ content: i18n.__("common.errorCommand") }).catch(console.error);
return;
}
if (!results || !results[0]) {
interaction.editReply({ content: i18n.__("search.noResults") });
return;
}
const options = results!.map((video) => {
return {
label: video.title ?? "",
value: video.url
};
});
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
.setCustomId("search-select")
.setPlaceholder("Nothing selected")
.setMinValues(1)
.setMaxValues(10)
.addOptions(options)
);
const followUp = await interaction.followUp({
content: "Choose songs to play",
components: [row]
});
followUp
.awaitMessageComponent({
time: 30000
})
.then((selectInteraction) => {
if (!(selectInteraction instanceof StringSelectMenuInteraction)) return;
selectInteraction.update({ content: "⏳ Loading the selected songs...", components: [] });
bot.slashCommandsMap
.get("play")!
.execute(interaction, selectInteraction.values[0])
.then(() => {
selectInteraction.values.slice(1).forEach((url) => {
bot.slashCommandsMap.get("play")!.execute(interaction, url);
});
});
})
.catch(console.error);
}
};
+31
View File
@@ -0,0 +1,31 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("shuffle").setDescription(i18n.__("shuffle.description")),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!queue)
return interaction.reply({ content: i18n.__("shuffle.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!guildMemer || !canModifyQueue(guildMemer)) return i18n.__("common.errorNotChannel");
let songs = queue.songs;
for (let i = songs.length - 1; i > 1; i--) {
let j = 1 + Math.floor(Math.random() * i);
[songs[i], songs[j]] = [songs[j], songs[i]];
}
queue.songs = songs;
const content = i18n.__mf("shuffle.result", { author: interaction.user.id });
safeReply(interaction, content);
}
};
+21
View File
@@ -0,0 +1,21 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("skip").setDescription(i18n.__("skip.description")),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!queue) return interaction.reply(i18n.__("skip.errorNotQueue")).catch(console.error);
if (!canModifyQueue(guildMemer!)) return i18n.__("common.errorNotChannel");
queue.player.stop(true);
safeReply(interaction, i18n.__mf("skip.result", { author: interaction.user.id }));
}
};
+51
View File
@@ -0,0 +1,51 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
export default {
data: new SlashCommandBuilder()
.setName("skipto")
.setDescription(i18n.__("skipto.description"))
.addIntegerOption((option) =>
option.setName("number").setDescription(i18n.__("skipto.args.number")).setRequired(true)
),
execute(interaction: ChatInputCommandInteraction) {
const playlistSlotArg = interaction.options.getInteger("number");
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!playlistSlotArg || isNaN(playlistSlotArg))
return interaction
.reply({
content: i18n.__mf("skipto.usageReply", { prefix: bot.prefix, name: module.exports.name }),
ephemeral: true
})
.catch(console.error);
const queue = bot.queues.get(interaction.guild!.id);
if (!queue)
return interaction.reply({ content: i18n.__("skipto.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!canModifyQueue(guildMemer!)) return i18n.__("common.errorNotChannel");
if (playlistSlotArg > queue.songs.length)
return interaction
.reply({ content: i18n.__mf("skipto.errorNotValid", { length: queue.songs.length }), ephemeral: true })
.catch(console.error);
if (queue.loop) {
for (let i = 0; i < playlistSlotArg - 2; i++) {
queue.songs.push(queue.songs.shift()!);
}
} else {
queue.songs = queue.songs.slice(playlistSlotArg - 2);
}
queue.player.stop();
interaction
.reply({ content: i18n.__mf("skipto.result", { author: interaction.user.id, arg: playlistSlotArg - 1 }) })
.catch(console.error);
}
};
+20
View File
@@ -0,0 +1,20 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
import { safeReply } from "../utils/safeReply";
export default {
data: new SlashCommandBuilder().setName("stop").setDescription(i18n.__("stop.description")),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
if (!queue) return interaction.reply(i18n.__("stop.errorNotQueue")).catch(console.error);
if (!guildMemer || !canModifyQueue(guildMemer)) return i18n.__("common.errorNotChannel");
queue.stop();
safeReply(interaction, i18n.__mf("stop.result", { author: interaction.user.id }));
}
};
+21
View File
@@ -0,0 +1,21 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
export default {
data: new SlashCommandBuilder().setName("uptime").setDescription(i18n.__("uptime.description")),
execute(interaction: ChatInputCommandInteraction) {
let seconds = Math.floor(bot.client.uptime! / 1000);
let minutes = Math.floor(seconds / 60);
let hours = Math.floor(minutes / 60);
let days = Math.floor(hours / 24);
seconds %= 60;
minutes %= 60;
hours %= 24;
return interaction
.reply({ content: i18n.__mf("uptime.result", { days: days, hours: hours, minutes: minutes, seconds: seconds }) })
.catch(console.error);
}
};
+38
View File
@@ -0,0 +1,38 @@
import { ChatInputCommandInteraction, SlashCommandBuilder } from "discord.js";
import { bot } from "../index";
import { i18n } from "../utils/i18n";
import { canModifyQueue } from "../utils/queue";
export default {
data: new SlashCommandBuilder()
.setName("volume")
.setDescription(i18n.__("volume.description"))
.addIntegerOption((option) => option.setName("volume").setDescription(i18n.__("volume.description"))),
execute(interaction: ChatInputCommandInteraction) {
const queue = bot.queues.get(interaction.guild!.id);
const guildMemer = interaction.guild!.members.cache.get(interaction.user.id);
const volumeArg = interaction.options.getInteger("volume");
if (!queue)
return interaction.reply({ content: i18n.__("volume.errorNotQueue"), ephemeral: true }).catch(console.error);
if (!canModifyQueue(guildMemer!))
return interaction.reply({ content: i18n.__("volume.errorNotChannel"), ephemeral: true }).catch(console.error);
if (!volumeArg || volumeArg === queue.volume)
return interaction
.reply({ content: i18n.__mf("volume.currentVolume", { volume: queue.volume }) })
.catch(console.error);
if (isNaN(volumeArg))
return interaction.reply({ content: i18n.__("volume.errorNotNumber"), ephemeral: true }).catch(console.error);
if (Number(volumeArg) > 100 || Number(volumeArg) < 0)
return interaction.reply({ content: i18n.__("volume.errorNotValid"), ephemeral: true }).catch(console.error);
queue.volume = volumeArg;
queue.resource.volume?.setVolumeLogarithmic(volumeArg / 100);
return interaction.reply({ content: i18n.__mf("volume.result", { arg: volumeArg }) }).catch(console.error);
}
};