Add an overlay soundboard and fix playback command bugs.
Stop was advancing the queue, history overwrote the day file, and slash commands often never replied; soundboard clips now mix on top of the current track. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
132
src/commands/soundboard.ts
Normal file
132
src/commands/soundboard.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
AutocompleteInteraction,
|
||||
CacheType,
|
||||
ChatInputCommandInteraction,
|
||||
SlashCommandBuilder,
|
||||
} from 'discord.js';
|
||||
import {
|
||||
addSound,
|
||||
buildSoundboardMessage,
|
||||
listSounds,
|
||||
playById,
|
||||
removeSound,
|
||||
} from '../soundboard';
|
||||
|
||||
const name = "soundboard"
|
||||
|
||||
function register() {
|
||||
return new SlashCommandBuilder()
|
||||
.setName(name)
|
||||
.setDescription('Soundboard — dźwięki na wierzchu muzyki')
|
||||
.addSubcommand((sub) => sub
|
||||
.setName("add")
|
||||
.setDescription("Dodaj dźwięk (max 10s)")
|
||||
.addAttachmentOption((option) => option
|
||||
.setName("file")
|
||||
.setDescription("Krótki plik audio")
|
||||
.setRequired(true))
|
||||
.addStringOption((option) => option
|
||||
.setName("description")
|
||||
.setDescription("Krótki opis na przycisku")
|
||||
.setRequired(true)
|
||||
.setMaxLength(40))
|
||||
.addStringOption((option) => option
|
||||
.setName("emoji")
|
||||
.setDescription("Emoji do przycisku")
|
||||
.setRequired(true)
|
||||
.setMaxLength(32)))
|
||||
.addSubcommand((sub) => sub
|
||||
.setName("list")
|
||||
.setDescription("Pokaż soundboard do klikania"))
|
||||
.addSubcommand((sub) => sub
|
||||
.setName("play")
|
||||
.setDescription("Puść dźwięk z listy")
|
||||
.addStringOption((option) => option
|
||||
.setName("sound")
|
||||
.setDescription("Który dźwięk")
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)))
|
||||
.addSubcommand((sub) => sub
|
||||
.setName("remove")
|
||||
.setDescription("Usuń dźwięk")
|
||||
.addStringOption((option) => option
|
||||
.setName("sound")
|
||||
.setDescription("Który dźwięk")
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)))
|
||||
}
|
||||
|
||||
export async function handleSoundboardAutocomplete(interaction: AutocompleteInteraction<CacheType>) {
|
||||
const focused = interaction.options.getFocused().toLowerCase();
|
||||
const choices = listSounds()
|
||||
.filter((sound) =>
|
||||
sound.description.toLowerCase().includes(focused) ||
|
||||
sound.emoji.includes(focused) ||
|
||||
sound.id.startsWith(focused)
|
||||
)
|
||||
.slice(0, 25)
|
||||
.map((sound) => ({
|
||||
name: `${sound.emoji} ${sound.description}`.slice(0, 100),
|
||||
value: sound.id,
|
||||
}));
|
||||
await interaction.respond(choices);
|
||||
}
|
||||
|
||||
async function execute(interaction: ChatInputCommandInteraction<CacheType>) {
|
||||
const sub = interaction.options.getSubcommand();
|
||||
try {
|
||||
if (sub === "add") {
|
||||
await interaction.deferReply();
|
||||
const file = interaction.options.getAttachment("file", true);
|
||||
const description = interaction.options.getString("description", true);
|
||||
const emoji = interaction.options.getString("emoji", true);
|
||||
const sound = await addSound({
|
||||
attachment: file,
|
||||
description,
|
||||
emoji,
|
||||
user: interaction.user.username,
|
||||
});
|
||||
await interaction.editReply(`Dodane: ${sound.emoji} **${sound.description}**`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub === "list") {
|
||||
await interaction.reply(buildSoundboardMessage(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub === "play") {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const id = interaction.options.getString("sound", true);
|
||||
const sound = await playById(id, interaction);
|
||||
await interaction.editReply(`${sound.emoji} ${sound.description}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub === "remove") {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const id = interaction.options.getString("sound", true);
|
||||
const removed = removeSound(id);
|
||||
if (!removed) {
|
||||
await interaction.editReply("Nie ma takiego dźwięku");
|
||||
return;
|
||||
}
|
||||
await interaction.editReply(`Usunięte: ${removed.emoji} ${removed.description}`);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
const message = error instanceof Error ? error.message : "Coś poszło nie tak :/";
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
await interaction.editReply(message);
|
||||
} else {
|
||||
await interaction.reply({ content: message, ephemeral: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name,
|
||||
register,
|
||||
execute
|
||||
}
|
||||
Reference in New Issue
Block a user