SamDizzle420

Bot

Jul 14th, 2023 (edited)
142
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const { Client } = require('discord.js');
  2. const { SlashCommandBuilder } = require('discord.js-slash-command');
  3. const { createAudioPlayer, createAudioResource, joinVoiceChannel, AudioPlayerStatus, NoSubscriberBehavior } = require('@discordjs/voice');
  4. const ytdl = require('ytdl-core');
  5. const youtubeDl = require('youtube-dl-exec');
  6. const SoundCloudDownloader = require('soundcloud-downloader');
  7. const SpotifyWebApi = require('spotify-web-api-node');
  8. const { GatewayIntentBits } = require('discord.js');
  9. require('dotenv').config();
  10. const { getInfo } = require('ytdl-core');
  11. const { EmbedBuilder } = require('discord.js');
  12. const { ActionRowBuilder } = require('discord.js');
  13. const { ButtonBuilder } = require('discord.js');
  14. const { ButtonStyle } = require('discord.js');
  15.  
  16. const spotifyApi = new SpotifyWebApi({
  17.   clientId: process.env.SPOTIFY_CLIENT_ID,
  18.   clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
  19. });
  20.  
  21. async function getAccessToken() {
  22.   const data = await spotifyApi.clientCredentialsGrant();
  23.   return data.body.access_token;
  24. }
  25.  
  26. async function setAccessToken() {
  27.   const accessToken = await getAccessToken();
  28.   spotifyApi.setAccessToken(accessToken);
  29. }
  30.  
  31. const client = new Client({
  32.   intents: [
  33.     GatewayIntentBits.Guilds,
  34.     GatewayIntentBits.GuildVoiceStates
  35.   ]
  36. });
  37.  
  38. const queue = new Map();
  39. const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause } });
  40.  
  41. client.on('ready', () => {
  42.   console.log(`Logged in as ${client.user.tag}`);
  43.   registerSlashCommands();
  44. });
  45.  
  46. client.on('interactionCreate', async (interaction) => {
  47.   if (!interaction.isCommand()) return;
  48.  
  49.   const { commandName, options } = interaction;
  50.  
  51.   if (commandName === 'play') {
  52.     const query = options.getString('query');
  53.     const voiceChannel = interaction.member.voice.channel;
  54.     if (!voiceChannel) {
  55.       return interaction.reply({ content: 'You need to be in a voice channel to use this command!', ephemeral: true });
  56.     }
  57.  
  58.     const connection = joinVoiceChannel({
  59.       channelId: voiceChannel.id,
  60.       guildId: voiceChannel.guild.id,
  61.       adapterCreator: voiceChannel.guild.voiceAdapterCreator,
  62.     });
  63.  
  64.     try {
  65.       const trackInfo = await getTrackInfo(query);
  66.       const resource = await createAudioResource(trackInfo.url);
  67.       player.play(resource);
  68.  
  69.       const serverQueue = getQueue(interaction.guildId);
  70.       serverQueue.songs.push(trackInfo);
  71.  
  72.       if (!serverQueue.playing) {
  73.         playSong(interaction.guildId);
  74.       }
  75.  
  76.       const embed = createNowPlayingEmbed(trackInfo);
  77.       const row = createPlaybackButtons();
  78.       interaction.reply({ embeds: [embed], components: [row] });
  79.     } catch (error) {
  80.       console.error(error);
  81.       interaction.reply({ content: 'An error occurred while playing the track.', ephemeral: true });
  82.     }
  83.   } else if (commandName === 'stop') {
  84.     stopPlayback(interaction.guildId);
  85.     interaction.reply('Stopped playback.');
  86.   } else if (commandName === 'queue') {
  87.     const serverQueue = getQueue(interaction.guildId);
  88.     if (serverQueue.songs.length === 0) {
  89.       interaction.reply('The queue is empty.');
  90.     } else {
  91.       const queueList = serverQueue.songs.map((song, index) => `${index + 1}. ${song.title}`);
  92.       interaction.reply(`Queue:\n${queueList.join('\n')}`);
  93.     }
  94.   }
  95. });
  96.  
  97. async function getTrackInfo(query) {
  98.   if (!query || query.trim().length === 0) {
  99.     throw new Error('Invalid query.');
  100.   }
  101.  
  102.   if (ytdl.validateURL(query)) {
  103.     const info = await ytdl.getInfo(query);
  104.     return {
  105.       url: info.videoDetails.video_url,
  106.       title: info.videoDetails.title,
  107.       thumbnail: info.videoDetails.thumbnails[0].url,
  108.       duration: parseInt(info.videoDetails.lengthSeconds),
  109.     };
  110.   } else if (query.includes('soundcloud.com')) {
  111.     const info = await SoundCloudDownloader.download(query);
  112.     return {
  113.       url: info.url,
  114.       title: info.title,
  115.       thumbnail: info.thumbnail,
  116.       duration: parseInt(info.duration),
  117.     };
  118.   } else if (query.includes('spotify.com')) {
  119.     const match = query.match(/track\/(\w+)/);
  120.     if (match) {
  121.       try {
  122.         await setAccessToken();
  123.         const trackId = match[1];
  124.         const data = await spotifyApi.getTrack(trackId);
  125.         const track = data.body;
  126.         return {
  127.           url: track.external_urls.spotify,
  128.           title: `${track.name} - ${track.artists[0].name}`,
  129.           thumbnail: track.album.images[0].url,
  130.           duration: Math.floor(track.duration_ms / 1000),
  131.         };
  132.       } catch (error) {
  133.         throw new Error('Failed to fetch track information from Spotify.');
  134.       }
  135.     } else {
  136.       throw new Error('Invalid Spotify track URL.');
  137.     }
  138.   } else {
  139.     throw new Error('Unsupported URL or search query.');
  140.   }
  141. }
  142.  
  143. function getQueue(guildId) {
  144.   if (!queue.has(guildId)) {
  145.     queue.set(guildId, { songs: [], playing: false });
  146.   }
  147.   return queue.get(guildId);
  148. }
  149.  
  150. function playSong(guildId) {
  151.   const serverQueue = getQueue(guildId);
  152.  
  153.   if (serverQueue.songs.length === 0) {
  154.     serverQueue.playing = false;
  155.     return;
  156.   }
  157.  
  158.   const currentSong = serverQueue.songs[0];
  159.   const resource = createAudioResource(currentSong.url);
  160.   player.play(resource);
  161.  
  162.   player.on(AudioPlayerStatus.Idle, () => {
  163.     serverQueue.songs.shift();
  164.     playSong(guildId);
  165.  
  166.     const nowPlayingEmbed = createNowPlayingEmbed(serverQueue.songs[0]);
  167.     const nowPlayingMessage = client.channels.cache.get(serverQueue.textChannelId).messages.cache.get(serverQueue.nowPlayingMessageId);
  168.     nowPlayingMessage.edit({ embeds: [nowPlayingEmbed] });
  169.   });
  170.  
  171.   serverQueue.playing = true;
  172. }
  173.  
  174. function stopPlayback(guildId) {
  175.   const serverQueue = getQueue(guildId);
  176.   serverQueue.songs = [];
  177.   player.stop();
  178. }
  179.  
  180. function createNowPlayingEmbed(songInfo) {
  181.   const embed = new EmbedBuilder()
  182.     .setColor('#FF0000')
  183.     .setTitle('Now Playing')
  184.     .setDescription(songInfo.title)
  185.     .setThumbnail(songInfo.thumbnail)
  186.     .addFields(
  187.       { name: 'Duration', value: formatDuration(songInfo.duration) },
  188.       { name: 'Progress', value: '▶️' + createProgressBar(songInfo.duration, player.state.resource.playbackDuration) }
  189.     );
  190.  
  191.   return embed;
  192. }
  193. function createPlaybackButtons() {
  194.   const playButton = new ButtonBuilder()
  195.     .setCustomId('play')
  196.     .setLabel('▶️ Play')
  197.     .setStyle(ButtonStyle.Primary)
  198.  
  199.   const pauseButton = new ButtonBuilder()
  200.     .setCustomId('pause')
  201.     .setLabel('⏸️ Pause')
  202.     .setStyle(ButtonStyle.Primary)
  203.  
  204.   const nextButton = new ButtonBuilder()
  205.     .setCustomId('next')
  206.     .setLabel('⏭️ Next')
  207.     .setStyle(ButtonStyle.Primary)
  208.  
  209.   const previousButton = new ButtonBuilder()
  210.     .setCustomId('previous')
  211.     .setLabel('⏮️ Previous')
  212.     .setStyle(ButtonStyle.Primary)
  213.  
  214.   const row = new ActionRowBuilder().addComponents(playButton, pauseButton, previousButton, nextButton);
  215.  
  216.   return row;
  217. }
  218.  
  219. function formatDuration(duration) {
  220.   const minutes = Math.floor(duration / 60);
  221.   const seconds = duration % 60;
  222.   return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  223. }
  224.  
  225. function createProgressBar(totalSeconds, currentSeconds) {
  226.     const length = 15;
  227.     const progress = Math.floor((currentSeconds / totalSeconds) * length);
  228.     const bar = '▬'.repeat(progress) + '🔘' + '▬'.repeat(length - progress);
  229.     return bar;
  230.   }
  231.  
  232.   function registerSlashCommands() {
  233.     client.guilds.cache.forEach(async (guild) => {
  234.       try {
  235.         await guild.commands.set([
  236.           {
  237.             name: 'play',
  238.             description: 'Play a song',
  239.             options: [
  240.               {
  241.                 name: 'query',
  242.                 description: 'Song name or URL',
  243.                 type: 3,
  244.                 required: true,
  245.               },
  246.             ],
  247.           },
  248.           {
  249.             name: 'stop',
  250.             description: 'Stop playback',
  251.           },
  252.           {
  253.             name: 'queue',
  254.             description: 'Show the current song queue',
  255.           },
  256.         ]);
  257.         console.log(`Registered slash commands for guild ${guild.name}`);
  258.       } catch (error) {
  259.         console.error(`Failed to register slash commands for guild ${guild.name}:`, error);
  260.       }
  261.     });
  262.   }
  263.  
  264.   client.login(process.env.TOKEN);
Advertisement
Add Comment
Please, Sign In to add comment