discord-multipurpose-bot/commands/music/shuffle.js
Ayden cb5a906850
Some checks are pending
Docker / build (push) Waiting to run
Feat/Add Music Commands (#1)
* add simple music functionality

* update workflow

* update Dockerfile

* update Dockerfile

* update Dockerfile

* update Dockerfile

* add few more music commands

* add lyrics command

* update lyrics command

* add loop, and add categories to all commands

* change discord status

* seperate distube and change startup console theme

* Update README

* UPDATE LICENSE file

* fix docker compose image, add better error handling for distube and update tagging workflow

* switch to node-alpine image for docker

* switch to node-alpine image for docker

* update ascii

* music commands imporvements, implement live lyrics, some guards and bot leaving on empty

* use ffmpeg package rather than ffmpeg-static
2025-09-21 01:26:18 +01:00

79 lines
2.5 KiB
JavaScript

const { SlashCommandBuilder } = require("discord.js");
const { requireVC, requireQueue } = require("../../utils/musicGuards");
function fisherYates(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
module.exports = {
data: new SlashCommandBuilder()
.setName("shuffle")
.setDescription("Shuffles the up-next songs (keeps the current track).")
.addIntegerOption((o) =>
o
.setName("amount")
.setDescription(
"Only shuffle the first N upcoming songs (default: all)."
)
.setMinValue(2)
),
category: "Music",
async execute(interaction, client) {
try {
await interaction.deferReply();
requireVC(interaction);
const queue = requireQueue(client, interaction);
const total = queue.songs.length;
if (total <= 2) {
// 0 or 1 upcoming track is not worth shuffling
return interaction.followUp({
content: "❌ Not enough songs to shuffle.",
ephemeral: true,
});
}
const upcoming = queue.songs.slice(1); // exclude the currently playing track
const amountOpt = interaction.options.getInteger("amount");
const amount = Math.min(
Math.max(amountOpt ?? upcoming.length, 2),
upcoming.length
);
// If user didn't specify an amount, prefer DisTube's built-in shuffle
if (amountOpt == null && typeof queue.shuffle === "function") {
// DisTube's shuffle shuffles upcoming by default (keeps current)
queue.shuffle();
return interaction.followUp(
`🔀 Shuffled **${upcoming.length}** upcoming track(s)!`
);
}
// Manual partial shuffle (first N upcoming)
const head = upcoming.slice(0, amount);
const tail = upcoming.slice(amount);
fisherYates(head);
// Splice back into queue: [ current, ...shuffledHead, ...tail ]
queue.songs.splice(1, amount, ...head);
// tail is already in place so no need to modify if amount === upcoming.length
return interaction.followUp(
`🔀 Shuffled the next **${amount}** track(s).`
);
} catch (e) {
console.error("shuffle command failed:", e);
const msg = e?.message || "❌ Failed to shuffle the queue.";
if (interaction.deferred || interaction.replied) {
return interaction.followUp({ content: msg, ephemeral: true });
}
return interaction.reply({ content: msg, ephemeral: true });
}
},
};