Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const {
- joinVoiceChannel,
- createAudioPlayer,
- createAudioResource,
- AudioPlayerStatus,
- StreamType,
- } = require('@discordjs/voice');
- const { EmbedBuilder } = require('discord.js');
- const { getVideoTitle, searchTrack } = require('./yt-dlp');
- const { getTrackData, saveCache } = require('./cacheManager');
- // Maps for per-guild states
- const playerMap = new Map();
- const queueMap = new Map();
- const playingMap = new Map();
- const volumeMap = new Map();
- const autoplayMap = new Map();
- const channelMap = new Map();
- const loopMap = new Map();
- // Voice channel connection
- function joinChannel(channel, guild) {
- return joinVoiceChannel({
- channelId: channel.id,
- guildId: guild.id,
- adapterCreator: guild.voiceAdapterCreator,
- });
- }
- // Player creation
- function createPlayer() {
- return createAudioPlayer();
- }
- // Text channel mapping
- function setTextChannel(guildId, channel) {
- channelMap.set(guildId, channel);
- }
- function getTextChannel(guildId) {
- return channelMap.get(guildId);
- }
- // Create styled embed
- function createPinkEmbed(title, description = '', fields = [], footerText = 'Music Bot đĩ') {
- return new EmbedBuilder()
- .setColor('#FF69B4')
- .setTitle(title)
- .setDescription(description || 'No description provided')
- .addFields(fields)
- .setFooter({ text: footerText });
- }
- // Add track to queue (fixed version)
- async function addToQueue(guildId, songQuery, message) {
- const queue = queueMap.get(guildId) || [];
- queueMap.set(guildId, queue);
- try {
- const cached = await getTrackData(songQuery);
- if (cached) {
- queue.push(cached);
- return {
- embeds: [createPinkEmbed(
- 'đļ Added to queue (from cache)',
- `**${cached.title}**`,
- [
- { name: 'Source', value: 'YouTube', inline: true },
- { name: 'Requested by', value: message.author.username, inline: true },
- { name: 'Link', value: `[Watch on YouTube](${cached.link})` },
- ]
- )],
- };
- }
- const track = await searchTrack(songQuery);
- if (!track) {
- return {
- embeds: [createPinkEmbed('â ī¸ Track not found', 'Try a different search query.')],
- };
- }
- const { title, audioUrl, videoId, thumbnail } = track;
- const link = `https://youtube.com/watch?v=${videoId}`;
- const song = {
- songQuery,
- originalQuery: songQuery,
- user: message.author.username,
- title,
- audioUrl,
- link,
- thumbnail,
- };
- queue.push(song);
- await saveCache({ [songQuery]: song });
- return {
- embeds: [createPinkEmbed(
- 'đļ Added to queue',
- `**${title}**`,
- [
- { name: 'Source', value: 'YouTube', inline: true },
- { name: 'Requested by', value: message.author.username, inline: true },
- { name: 'Link', value: `[Watch on YouTube](${link})` },
- ]
- )],
- };
- } catch (err) {
- console.error('â Error in addToQueue:', err);
- return {
- embeds: [createPinkEmbed('â ī¸ Failed to add track', 'Something went wrong. Try again.')],
- };
- }
- }
- // Play the next track in queue
- async function handleQueue(player, connection, guildId) {
- const queue = queueMap.get(guildId);
- if (!queue?.length || playingMap.get(guildId)) return;
- const song = queue.shift();
- const { title, user, audioUrl, link, thumbnail } = song;
- playingMap.set(guildId, true);
- try {
- const resource = createAudioResource(audioUrl, {
- inputType: StreamType.Arbitrary,
- metadata: { title },
- inlineVolume: true,
- });
- const volume = volumeMap.get(guildId) || 1.0;
- resource.volume.setVolume(volume);
- player.play(resource);
- connection.subscribe(player);
- const textChannel = getTextChannel(guildId);
- if (textChannel) {
- const videoId = getYouTubeID(link);
- const embed = createPinkEmbed(
- 'đļ Now playing',
- `**${title}**`,
- [
- { name: 'Source', value: 'YouTube', inline: true },
- { name: 'Requested by', value: user, inline: true },
- { name: 'Link', value: `[Watch on YouTube](${link})` },
- ]
- ).setThumbnail(thumbnail || `https://img.youtube.com/vi/${videoId}/mqdefault.jpg`);
- textChannel.send({ embeds: [embed] });
- }
- player.removeAllListeners();
- player.once(AudioPlayerStatus.Idle, async () => {
- if (loopMap.get(guildId)) queue.unshift(song);
- playingMap.set(guildId, false);
- await handleQueue(player, connection, guildId);
- });
- player.once('error', error => {
- console.error('â Audio Player Error:', error);
- playingMap.set(guildId, false);
- handleQueue(player, connection, guildId);
- });
- } catch (err) {
- console.error('â Error handling queue:', err);
- playingMap.set(guildId, false);
- handleQueue(player, connection, guildId);
- }
- }
- // Helpers
- function getYouTubeID(url) {
- const match = url.match(/(youtu\.be\/|v=)([^#&?]{11})/);
- return match ? match[2] : null;
- }
- function getPlayer(guildId) {
- return playerMap.get(guildId);
- }
- function setPlayer(guildId, player) {
- if (player) playerMap.set(guildId, player);
- else playerMap.delete(guildId);
- }
- function skipSong(guildId) {
- const player = getPlayer(guildId);
- if (!player) return { embeds: [createPinkEmbed('â ī¸ Nothing is playing')] };
- player.stop();
- return { embeds: [createPinkEmbed('âī¸ Skipped to next song')] };
- }
- function stopPlayback(guildId, connection) {
- const player = getPlayer(guildId);
- if (!player) return { embeds: [createPinkEmbed('â ī¸ Nothing is playing')] };
- queueMap.set(guildId, []);
- player.stop();
- connection.destroy();
- return { embeds: [createPinkEmbed('âšī¸ Stopped playback and cleared queue')] };
- }
- function toggleAutoplay(guildId) {
- const current = autoplayMap.get(guildId) || false;
- autoplayMap.set(guildId, !current);
- return {
- embeds: [
- createPinkEmbed(current ? 'đ Autoplay disabled' : 'đ Autoplay enabled'),
- ],
- };
- }
- function toggleLoop(guildId) {
- const current = loopMap.get(guildId) || false;
- loopMap.set(guildId, !current);
- return {
- embeds: [
- createPinkEmbed(current ? 'âĄī¸ Loop disabled' : 'đ Loop enabled'),
- ],
- };
- }
- function setVolume(guildId, volume) {
- const player = getPlayer(guildId);
- if (!player) return { embeds: [createPinkEmbed('â No active player')] };
- const clamped = Math.min(Math.max(volume, 0.0), 2.0);
- volumeMap.set(guildId, clamped);
- const resource = player.state.resource;
- if (resource) resource.volume.setVolume(clamped);
- return { embeds: [createPinkEmbed('đ Volume set', `${Math.round(clamped * 100)}%`)] };
- }
- // Exports
- module.exports = {
- joinChannel,
- createPlayer,
- playSong: handleQueue,
- getPlayer,
- setPlayer,
- addToQueue,
- handleQueue,
- skipSong,
- stopPlayback,
- toggleAutoplay,
- toggleLoop,
- setVolume,
- setTextChannel,
- // Expose maps for advanced control/debug
- queueMap,
- playingMap,
- playerMap,
- loopMap,
- };
Advertisement
Add Comment
Please, Sign In to add comment