const ytdl = require('ytdl-core'); const { Command } = require('discord.js-commando'); const { MessageEmbed } = require('discord.js'); const Youtube = require('simple-youtube-api'); const { youtubeAPI } = require('../../config.json'); const youtube = new Youtube('AIzaSyB9xJENORzZt-GmOGx4WsNCPgKSIxhJcds'); const emoji = require('emoji-random'); module.exports = class PlayVoice extends Command { constructor(client) { super(client, { name: 'play', group: 'voice', memberName: 'play', description: 'play a youtube video', guildOnly: true, clientPermissions: ['SPEAK', 'CONNECT'], args: [ { key: 'query', prompt: 'what song u wanna hear?', type: 'string', validate: function (query) { return query.length > 0 && query.length < 200; } } ], examples: [ 's5n!play https://www.youtube.com/watch?v=dQw4w9WgXcQ', 's5n!play despacito' ] }); } async run(msg, { query }) { const voiceChannel = msg.member.voice.channel; if (!voiceChannel) return msg.say('join a channel and try again ' + emoji.random()); if ( // if the user entered yt playlist url query.match( /^(?!.*\?.*\bv=)https:\/\/www\.youtube\.com\/.*\?.*\blist=.*$/ ) ) { const playlist = await youtube.getPlaylist(query).catch(function () { return msg.say('playlist is either private or it does not exist ' + emoji.random()); }); // remove the 10 if you removed the queue limit conditions below const videosObj = await playlist.getVideos(10).catch(function () { return msg.say( 'there was a problem getting one of the videos in the playlist ' + emoji.random() ); }); for (let i = 0; i < videosObj.length; i++) { const video = await videosObj[i].fetch(); // this can be uncommented if you choose to limit the queue // if (msg.guild.musicData.queue.length < 10) { // msg.guild.musicData.queue.push( this.constructSongObj(video, voiceChannel) ); // } else { // return msg.say( // `I can't play the full playlist because there will be more than 10 songs in queue` // ); // } } if (msg.guild.musicData.isPlaying == false) { msg.guild.musicData.isPlaying = true; return this.playSong(msg.guild.musicData.queue, msg); } else if (msg.guild.musicData.isPlaying == true) { return msg.say( `playlist - :musical_note: ${playlist.title} :musical_note: has been added to queue ` + emoji.random() ); } } // This if statement checks if the user entered a youtube url, it can be any kind of youtube url if (query.match(/^(http(s)?:\/\/)?((w){3}.)?youtu(be|.be)?(\.com)?\/.+/)) { query = query .replace(/(>|<)/gi, '') .split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/); const id = query[2].split(/[^0-9a-z_\-]/i)[0]; const video = await youtube.getVideoByID(id).catch(function () { return msg.say( 'there was a problem getting the video you provided ' + emoji.random() ); }); // // can be uncommented if you don't want the bot to play live streams // if (video.raw.snippet.liveBroadcastContent === 'live') { // return msg.say("I don't support live streams!"); // } // // can be uncommented if you don't want the bot to play videos longer than 1 hour // if (video.duration.hours !== 0) { // return msg.say('I cannot play videos longer than 1 hour'); // } // // can be uncommented if you want to limit the queue // if (msg.guild.musicData.queue.length > 10) { // return msg.say( // 'There are too many songs in the queue already, skip or wait a bit' // ); // } msg.guild.musicData.queue.push( this.constructSongObj(video, voiceChannel) ); if ( msg.guild.musicData.isPlaying == false || typeof msg.guild.musicData.isPlaying == 'undefined' ) { msg.guild.musicData.isPlaying = true; return this.playSong(msg.guild.musicData.queue, msg); } else if (msg.guild.musicData.isPlaying == true) { return msg.say(`${video.title} added to queue ` + emoji.random()); } } // if user provided a song/video name const videos = await youtube.searchVideos(query, 5).catch(function () { return msg.say( 'there was a problem searching the video you requested :( ' + emoji.random() ); }); if (videos.length < 5) { return msg.say( `i had some trouble finding what you were looking for, please try again or be more specific lol ` + emoji.random() ); } const vidNameArr = []; for (let i = 0; i < videos.length; i++) { vidNameArr.push(`${i + 1}: ${videos[i].title}`); } vidNameArr.push('exit'); const embed = new MessageEmbed() .setColor(0xF97DAE) .setTitle('choose a song by msging a number between 1 and 5 ' + emoji.random()) .addField(`‎`, '**song #**' + vidNameArr[0]) .addField(`‎`, '**song #**' + vidNameArr[1]) .addField(`‎`, '**song #**' + vidNameArr[2]) .addField(`‎`, '**song #**' + vidNameArr[3]) .addField(`‎`, '**song #**' + vidNameArr[4]) .addField(`‎`, '**exit selection**: ' + 'exit'); var songEmbed = await msg.channel.send({ embed }); var that = this; msg.channel .awaitMessages( function (msg) { return (msg.content > 0 && msg.content < 6) || msg.content === 'exit'; }, { max: 1, time: 60000, errors: ['time'] } ) .then(function (response) { const videoIndex = parseInt(response.first().content); if (response.first().content === 'exit') return songEmbed.delete(); youtube .getVideoByID(videos[videoIndex - 1].id) .then(function (video) { // // can be uncommented if you don't want the bot to play live streams // if (video.raw.snippet.liveBroadcastContent === 'live') { // songEmbed.delete(); // return msg.say("I don't support live streams!"); // } // // can be uncommented if you don't want the bot to play videos longer than 1 hour // if (video.duration.hours !== 0) { // songEmbed.delete(); // return msg.say('I cannot play videos longer than 1 hour'); // } // // can be uncommented if you don't want to limit the queue // if (msg.guild.musicData.queue.length > 10) { // songEmbed.delete(); // return msg.say( // 'There are too many songs in the queue already, skip or wait a bit' // ); // } msg.guild.musicData.queue.push( that.constructSongObj(video, voiceChannel) ); if (msg.guild.musicData.isPlaying == false) { msg.guild.musicData.isPlaying = true; if (songEmbed) { songEmbed.delete(); } that.playSong(msg.guild.musicData.queue, msg); } else if (msg.guild.musicData.isPlaying == true) { if (songEmbed) { songEmbed.delete(); } return msg.say(`${video.title} added to queue ` + emoji.random()); } }) .catch(function () { if (songEmbed) { songEmbed.delete(); } return msg.say( 'an error has occured when trying to get the video id from youtube ' + emoji.random() ); }); }) .catch(function () { if (songEmbed) { songEmbed.delete(); } return msg.say( 'try again and enter a number between 1 and 5 or exit ' + emoji.random() ); }); } playSong(queue, msg) { const classThis = this; // use classThis instead of 'this' because of lexical scope below queue[0].voiceChannel .join() .then(function (connection) { const dispatcher = connection .play( ytdl(queue[0].url, { quality: 'highestaudio', highWaterMark: 1024 * 1024 * 10 }) ) .on('start', function () { msg.guild.musicData.songDispatcher = dispatcher; const volume = 10 / 100; msg.guild.musicData.volume = volume; dispatcher.setVolume(msg.guild.musicData.volume); const videoEmbed = new MessageEmbed() .setThumbnail(queue[0].thumbnail) .setColor(0xF97DAE) .addField('now playing:', queue[0].title) .addField('duration:', queue[0].duration); if (queue[1]) videoEmbed.addField('next song:', queue[1].title); msg.say(videoEmbed); msg.guild.musicData.nowPlaying = queue[0]; return queue.shift(); }) .on('finish', function () { if (queue.length >= 1) { return classThis.playSong(queue, msg); } else { msg.guild.musicData.isPlaying = false; msg.guild.musicData.nowPlaying = null; msg.guild.musicData.songDispatcher = null; return msg.guild.me.voice.channel.leave(); } }) .on('error', function (e) { msg.say('can\'t play song ' + emoji.random()); console.error(e); msg.guild.musicData.queue.length = 0; msg.guild.musicData.isPlaying = false; msg.guild.musicData.nowPlaying = null; msg.guild.musicData.songDispatcher = null; return msg.guild.me.voice.channel.leave(); }); }) .catch(function (e) { console.error(e); return msg.guild.me.voice.channel.leave(); }); } constructSongObj(video, voiceChannel) { let duration = this.formatDuration(video.duration); if (duration == '00:00') duration = 'live stream'; return { url: `https://www.youtube.com/watch?v=${video.raw.id}`, title: video.title, duration, thumbnail: video.thumbnails.high.url, voiceChannel }; } // prettier-ignore formatDuration(durationObj) { const duration = `${durationObj.hours ? (durationObj.hours + ':') : ''}${ durationObj.minutes ? durationObj.minutes : '00' }:${ (durationObj.seconds < 10) ? ('0' + durationObj.seconds) : (durationObj.seconds ? durationObj.seconds : '00') }`; return duration; } };