2019-05-30 09:01:25 +00:00
const { Client , Util } = require ( 'discord.js' ) ;
const Discord = require ( 'discord.js' ) ;
const YouTube = require ( 'simple-youtube-api' )
const ytdl = require ( 'ytdl-core' ) ;
2019-06-09 19:33:55 +00:00
const PREFIX = ( '-' )
2019-05-30 09:01:25 +00:00
const client = new Client ( { disableEveryone : true } ) ;
2019-07-10 10:13:24 +00:00
const youtube = new YouTube ( process . env . API _KEY ) ;
2019-05-30 09:01:25 +00:00
const queue = new Map ( ) ;
2019-07-10 10:01:42 +00:00
client . on ( 'ready' , ( ) => {
2019-06-09 19:33:55 +00:00
client . user . setActivity ( '-help' , { type : 'LISTENING' } )
2019-05-30 09:01:25 +00:00
client . user . setStatus ( 'dnd' ) ;
} ) ;
2019-06-09 19:31:08 +00:00
client . on ( 'message' , async msg => {
2019-06-18 14:59:58 +00:00
if ( ! msg . guild || msg . author . bot ) return undefined ;
2019-06-18 15:24:11 +00:00
if ( msg . content . toUpperCase ( ) . startsWith ( ` MUSIX ` ) ) {
msg . channel . send ( '-help to see my commands.' )
}
2019-06-09 19:31:08 +00:00
if ( msg . content . startsWith ( ` ${ PREFIX } ` ) ) {
2019-06-18 15:22:29 +00:00
if ( msg . content === ` ${ PREFIX } ping ` ) {
2019-07-09 09:17:33 +00:00
msg . channel . send ( ` My current Ping: ** ${ Math . floor ( client . ping * 10 ) / 10 } ms**. ` )
2019-06-18 14:59:58 +00:00
return ;
}
2019-06-09 19:31:08 +00:00
if ( msg . content === ` ${ PREFIX } help ` ) {
const embed = new Discord . RichEmbed ( )
. setTitle ( 'Commands for Musix!' )
. addField ( '```-play```' , 'Play a song.' , true )
. addField ( '```-queue```' , 'Display the queue.' , true )
. addField ( '```-np```' , 'Display whats currently playing.' , true )
. addField ( '```-volume```' , 'Change or check the volume.' , true )
. addField ( '```-pause```' , 'Pause the music.' , true )
. addField ( '```-resume```' , 'Resume the music.' , true )
. addField ( '```-stop```' , 'Stop the music, Clear the queue and leave the current voice channel.' , true )
. addField ( '```-skip```' , 'Skip a song.' , true )
2019-06-10 05:37:21 +00:00
. addField ( '```-invite```' , 'Invite Musix.' , true )
. addField ( '```-info```' , 'Display info and instructions.' , true )
. addField ( '```-help```' , 'Display the help.' , true )
2019-06-09 19:31:08 +00:00
. setAuthor ( 'Musix' , 'https://cdn.discordapp.com/avatars/572405135658188800/04c6f22b7600ddecfbc245dd3ec10f9f.png?size=2048' )
. setColor ( '#b50002' )
msg . channel . send ( embed ) ;
return undefined ;
2019-06-05 13:29:58 +00:00
}
2019-06-09 19:31:08 +00:00
if ( msg . content === ` ${ PREFIX } info ` ) {
var line = '**>-----------------------------------------------------------------------<**' ;
2019-06-09 19:49:44 +00:00
var dj = msg . guild . roles . find ( x => x . name === 'DJ' ) ? true : false ;
2019-06-09 19:31:08 +00:00
const embed = new Discord . RichEmbed ( )
2019-06-09 19:42:05 +00:00
. setTitle ( '**Musix instructions and info**:' )
2019-06-09 19:49:44 +00:00
. addField ( 'If your current guild has a role called \'DJ\' you will need it to use music commands! If your current guild doesn\'t have a role called \'DJ\' everyone can use music commands!' , 'DJ role existance: ' + dj , true )
. addField ( 'If you encounter any errors with musix please report about them on the offical musix support server!' , 'https://discord.gg/rvHuJtB' , true )
. addField ( 'On errors you can do -stop to reset the queue and try again!' , line , true )
2019-06-18 17:58:36 +00:00
. addField ( 'Current Ping in milliseconds' , ` ${ client . ping } ` , true )
2019-06-09 19:31:08 +00:00
. setAuthor ( 'Musix' , 'https://cdn.discordapp.com/avatars/572405135658188800/04c6f22b7600ddecfbc245dd3ec10f9f.png?size=2048' )
. setColor ( '#b50002' )
msg . channel . send ( embed ) ;
return undefined ;
2019-06-05 13:29:58 +00:00
}
2019-06-09 19:42:05 +00:00
if ( msg . content === ` ${ PREFIX } invite ` ) {
2019-06-13 07:41:53 +00:00
msg . channel . send ( 'Invite me with: https://bit.ly/2V3D0p7' )
2019-06-09 19:31:08 +00:00
return undefined ;
2019-06-05 13:29:58 +00:00
}
2019-05-30 11:04:07 +00:00
if ( msg . member . guild . roles . find ( x => x . name === 'DJ' ) ) {
if ( msg . member . roles . find ( x => x . name === 'DJ' ) ) {
const args = msg . content . split ( ' ' ) ;
const searchString = args . slice ( 1 ) . join ( ' ' ) ;
const url = args [ 1 ] ? args [ 1 ] . replace ( /<(.+)>/g , '$1' ) : '' ;
const serverQueue = queue . get ( msg . guild . id ) ;
let command = msg . content . toLowerCase ( ) . split ( ' ' ) [ 0 ] ;
command = command . slice ( PREFIX . length )
if ( command === 'play' ) {
2019-06-09 19:37:54 +00:00
if ( ! args [ 1 ] ) return msg . channel . send ( ':x: I\'m sorry but you didn\'t specify a song' ) ;
2019-05-30 11:04:07 +00:00
const voiceChannel = msg . member . voiceChannel ;
if ( ! voiceChannel ) return msg . channel . send ( ':x: I\'m sorry but you need to be in a voice channel to play music!' ) ;
const permissions = voiceChannel . permissionsFor ( msg . client . user ) ;
if ( ! permissions . has ( 'CONNECT' ) ) {
return msg . channel . send ( ':x: I cannot connect to your voice channel, make sure I have the proper permissions!' ) ;
}
if ( ! permissions . has ( 'SPEAK' ) ) {
return msg . channel . send ( ':x: I cannot speak in this voice channel, make sure I have the proper permissions!' ) ;
2019-05-30 09:01:25 +00:00
}
2019-05-30 11:04:07 +00:00
if ( url . match ( /^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/ ) ) {
const playlist = await youtube . getPlaylist ( url ) ;
const videos = await playlist . getVideos ( ) ;
for ( const video of Object . values ( videos ) ) {
const video2 = await youtube . getVideoByID ( video . id ) ; // eslint-disable-line no-await-in-loop
await handleVideo ( video2 , msg , voiceChannel , true ) ; // eslint-disable-line no-await-in-loop
}
return msg . channel . send ( ` :white_check_mark: Playlist: ** ${ playlist . title } ** has been added to the queue! ` ) ;
} else {
2019-05-30 09:01:25 +00:00
try {
2019-05-30 11:04:07 +00:00
var video = await youtube . getVideo ( url ) ;
} catch ( error ) {
2019-05-30 09:01:25 +00:00
try {
2019-05-30 11:04:07 +00:00
var videos = await youtube . searchVideos ( searchString , 10 ) ;
let index = 0 ;
msg . channel . send ( `
_ _ * * Song selection : * * _ _
2019-05-30 18:05:16 +00:00
$ { videos . map ( video2 => ` ** ${ ++ index } -** ${ video2 . title } ` ) . join ( '\n' ) }
2019-05-30 18:14:31 +00:00
Please provide a value to select one of the search results ranging from _ _1 - 10__ .
2019-05-30 11:04:07 +00:00
` );
try {
var response = await msg . channel . awaitMessages ( msg2 => msg2 . content > 0 && msg2 . content < 11 , {
maxMatches : 1 ,
time : 10000 ,
errors : [ 'time' ]
} ) ;
} catch ( err ) {
2019-06-20 14:26:09 +00:00
return msg . channel . send ( ':x: No or invalid value entered, cancelling song selection.' ) ;
2019-05-30 11:04:07 +00:00
}
const videoIndex = parseInt ( response . first ( ) . content ) ;
var video = await youtube . getVideoByID ( videos [ videoIndex - 1 ] . id ) ;
2019-05-30 09:01:25 +00:00
} catch ( err ) {
2019-05-30 11:04:07 +00:00
return msg . channel . send ( ':x: I could not obtain any search results.' ) ;
2019-05-30 09:01:25 +00:00
}
}
2019-05-30 11:04:07 +00:00
return handleVideo ( video , msg , voiceChannel ) ;
2019-05-30 09:01:25 +00:00
}
2019-05-30 11:04:07 +00:00
} else if ( command === 'skip' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing that I could skip for you.' ) ;
2019-06-16 14:04:37 +00:00
serverQueue . connection . dispatcher . end ( 'Skipped' ) ;
2019-05-30 11:04:07 +00:00
return undefined ;
} else if ( command === 'stop' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing that I could stop for you.' ) ;
serverQueue . songs = [ ] ;
serverQueue . connection . dispatcher . end ( 'Stopped!' ) ;
return undefined ;
} else if ( command === 'volume' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing.' ) ;
if ( ! args [ 1 ] ) return msg . channel . send ( ` The current volume is: ** ${ serverQueue . volume } ** :speaker: ` ) ;
2019-06-18 07:53:04 +00:00
if ( isNaN ( args [ 1 ] ) ) {
return msg . channel . send ( ':x: I\'m sorry, But you need to enter a valid __number__.' )
}
2019-05-30 11:04:07 +00:00
serverQueue . volume = args [ 1 ] ;
2019-05-31 18:38:53 +00:00
serverQueue . connection . dispatcher . setVolumeLogarithmic ( args [ 1 ] / 5 ) ;
2019-05-30 11:04:07 +00:00
return msg . channel . send ( ` I set the volume to: ** ${ args [ 1 ] } ** 🔊 ` ) ;
} else if ( command === 'np' ) {
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing.' ) ;
return msg . channel . send ( ` :musical_note: Now playing: ** ${ serverQueue . songs [ 0 ] . title } ** ` ) ;
2019-07-18 16:36:36 +00:00
} else if ( command === "queue" ) {
if ( ! serverQueue )
return msg . channel . send ( ":x: There is nothing in the queue." ) ;
var queuemessage = ` __**Song queue:**__
$ { serverQueue . songs . map ( song => ` **-** ${ song . title } ` ) . join ( "\n" ) }
* * Now playing : * * $ { serverQueue . songs [ 0 ] . title } : musical _note : ` ;
if ( queuemessage . length < 2000 ) {
return msg . channel . send (
":x: The queue has too many songs in it to show all in this channel. Try again after a few songs"
) ;
}
return msg . channel . send ( queuemessage ) ;
2019-05-30 11:04:07 +00:00
} else if ( command === 'pause' ) {
if ( serverQueue && serverQueue . playing ) {
serverQueue . playing = false ;
serverQueue . connection . dispatcher . pause ( ) ;
return msg . channel . send ( ':pause_button: Paused the music for you!' ) ;
}
return msg . channel . send ( ':x: There is nothing playing.' ) ;
} else if ( command === 'resume' ) {
if ( serverQueue && ! serverQueue . playing ) {
serverQueue . playing = true ;
serverQueue . connection . dispatcher . resume ( ) ;
return msg . channel . send ( ':play_pause: Resumed the music for you!' ) ;
}
return msg . channel . send ( ':x: There is nothing playing.' ) ;
2019-05-30 09:01:25 +00:00
}
2019-06-13 07:43:06 +00:00
if ( msg . content === ` ${ PREFIX } ` ) return ;
2019-06-13 07:38:45 +00:00
msg . channel . send ( ':x: Unknown command! Type -help for the list of commands!' )
2019-05-30 09:01:25 +00:00
return undefined ;
2019-06-16 13:03:14 +00:00
}
2019-06-16 13:05:38 +00:00
if ( msg . content === ` ${ PREFIX } ` ) return ;
2019-07-10 11:18:20 +00:00
var coms = [ '-play' , '-queue' , '-np' , '-volume' , '-pause' , '-resume' , '-stop' , '-skip' ]
2019-06-16 14:04:37 +00:00
for ( var i = 0 ; i < coms . length ; i ++ ) {
2019-06-16 13:25:12 +00:00
if ( msg . content . includes ( coms [ i ] ) ) {
if ( ! msg . member . roles . find ( x => x . name === 'DJ' ) ) {
2019-06-16 14:57:55 +00:00
msg . channel . send ( ':x: i\'m sorry but you need to have the \'DJ\' role to use music commands!' )
2019-06-16 13:25:12 +00:00
return ;
}
2019-06-16 14:04:37 +00:00
}
2019-05-30 11:04:07 +00:00
}
2019-06-16 14:04:37 +00:00
msg . channel . send ( ':x: Unknown command! Type -help for the list of commands!' )
2019-06-16 14:08:35 +00:00
return ;
2019-05-30 11:04:07 +00:00
}
else {
const args = msg . content . split ( ' ' ) ;
const searchString = args . slice ( 1 ) . join ( ' ' ) ;
const url = args [ 1 ] ? args [ 1 ] . replace ( /<(.+)>/g , '$1' ) : '' ;
const serverQueue = queue . get ( msg . guild . id ) ;
let command = msg . content . toLowerCase ( ) . split ( ' ' ) [ 0 ] ;
command = command . slice ( PREFIX . length )
if ( command === 'play' ) {
if ( ! args [ 1 ] ) return msg . channel . send ( ':x: I think you forgot what you wanted to play!' ) ;
const voiceChannel = msg . member . voiceChannel ;
if ( ! voiceChannel ) return msg . channel . send ( ':x: I\'m sorry but you need to be in a voice channel to play music!' ) ;
const permissions = voiceChannel . permissionsFor ( msg . client . user ) ;
if ( ! permissions . has ( 'CONNECT' ) ) {
return msg . channel . send ( ':x: I cannot connect to your voice channel, make sure I have the proper permissions!' ) ;
}
if ( ! permissions . has ( 'SPEAK' ) ) {
return msg . channel . send ( ':x: I cannot speak in this voice channel, make sure I have the proper permissions!' ) ;
}
if ( url . match ( /^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/ ) ) {
const playlist = await youtube . getPlaylist ( url ) ;
const videos = await playlist . getVideos ( ) ;
for ( const video of Object . values ( videos ) ) {
const video2 = await youtube . getVideoByID ( video . id ) ; // eslint-disable-line no-await-in-loop
await handleVideo ( video2 , msg , voiceChannel , true ) ; // eslint-disable-line no-await-in-loop
}
return msg . channel . send ( ` :white_check_mark: Playlist: ** ${ playlist . title } ** has been added to the queue! ` ) ;
} else {
try {
var video = await youtube . getVideo ( url ) ;
} catch ( error ) {
try {
var videos = await youtube . searchVideos ( searchString , 10 ) ;
let index = 0 ;
msg . channel . send ( `
_ _ * * Song selection : * * _ _
2019-06-01 06:23:23 +00:00
$ { videos . map ( video2 => ` ** ${ ++ index } -** ${ video2 . title } ` ) . join ( '\n' ) }
Please provide a value to select one of the search results ranging from 1 - 10.
2019-05-30 11:04:07 +00:00
` );
// eslint-disable-next-line max-depth
try {
var response = await msg . channel . awaitMessages ( msg2 => msg2 . content > 0 && msg2 . content < 11 , {
maxMatches : 1 ,
time : 10000 ,
errors : [ 'time' ]
} ) ;
} catch ( err ) {
return msg . channel . send ( ':x: No or invalid value entered, cancelling video selection.' ) ;
}
const videoIndex = parseInt ( response . first ( ) . content ) ;
var video = await youtube . getVideoByID ( videos [ videoIndex - 1 ] . id ) ;
} catch ( err ) {
2019-07-10 10:11:50 +00:00
console . error ( err ) ;
2019-05-30 11:04:07 +00:00
return msg . channel . send ( ':x: I could not obtain any search results.' ) ;
}
}
return handleVideo ( video , msg , voiceChannel ) ;
}
} else if ( command === 'skip' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing that I could skip for you.' ) ;
msg . channel . send ( 'Skipped :thumbsup:' )
serverQueue . connection . dispatcher . end ( 'Skipped' ) ;
return undefined ;
} else if ( command === 'stop' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing that I could stop for you.' ) ;
msg . channel . send ( 'Stopped the music! :stop_button:' )
serverQueue . songs = [ ] ;
serverQueue . connection . dispatcher . end ( 'Stopped!' ) ;
return undefined ;
} else if ( command === 'volume' ) {
if ( ! msg . member . voiceChannel ) return msg . channel . send ( ':x: You are not in a voice channel!' ) ;
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing.' ) ;
if ( ! args [ 1 ] ) return msg . channel . send ( ` The current volume is: ** ${ serverQueue . volume } ** :speaker: ` ) ;
2019-06-18 07:54:46 +00:00
if ( isNaN ( args [ 1 ] ) ) {
return msg . channel . send ( ':x: I\'m sorry, But you need to enter a valid __number__.' )
}
2019-05-30 11:04:07 +00:00
serverQueue . volume = args [ 1 ] ;
2019-05-31 18:38:53 +00:00
serverQueue . connection . dispatcher . setVolumeLogarithmic ( args [ 1 ] / 5 ) ;
2019-05-30 11:04:07 +00:00
return msg . channel . send ( ` I set the volume to: ** ${ args [ 1 ] } ** 🔊 ` ) ;
} else if ( command === 'np' ) {
if ( ! serverQueue ) return msg . channel . send ( ':x: There is nothing playing.' ) ;
return msg . channel . send ( ` :musical_note: Now playing: ** ${ serverQueue . songs [ 0 ] . title } ** ` ) ;
2019-07-18 16:36:36 +00:00
} else if ( command === "queue" ) {
if ( ! serverQueue )
return msg . channel . send ( ":x: There is nothing in the queue." ) ;
var queuemessage = ` __**Song queue:**__
$ { serverQueue . songs . map ( song => ` **-** ${ song . title } ` ) . join ( "\n" ) }
* * Now playing : * * $ { serverQueue . songs [ 0 ] . title } : musical _note : ` ;
if ( queuemessage . length < 2000 ) {
return msg . channel . send (
":x: The queue has too many songs in it to show all in this channel. Try again after a few songs"
) ;
}
return msg . channel . send ( queuemessage ) ;
2019-05-30 11:04:07 +00:00
} else if ( command === 'pause' ) {
if ( serverQueue && serverQueue . playing ) {
serverQueue . playing = false ;
serverQueue . connection . dispatcher . pause ( ) ;
return msg . channel . send ( ':pause_button: Paused the music for you!' ) ;
}
return msg . channel . send ( ':x: There is nothing playing.' ) ;
} else if ( command === 'resume' ) {
if ( serverQueue && ! serverQueue . playing ) {
serverQueue . playing = true ;
serverQueue . connection . dispatcher . resume ( ) ;
return msg . channel . send ( ':play_pause: Resumed the music for you!' ) ;
}
return msg . channel . send ( ':x: There is nothing playing.' ) ;
2019-05-30 09:01:25 +00:00
}
2019-05-30 11:04:07 +00:00
}
2019-06-10 05:38:23 +00:00
if ( msg . content === ` ${ PREFIX } ` ) {
return undefined ;
}
2019-06-09 19:49:44 +00:00
msg . channel . send ( ':x: Unknown command! Type -help for the list of commands!' )
2019-06-10 05:32:29 +00:00
return undefined ;
2019-05-30 09:01:25 +00:00
}
} ) ;
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
async function handleVideo ( video , msg , voiceChannel , playlist = false ) {
const serverQueue = queue . get ( msg . guild . id ) ;
const song = {
id : video . id ,
title : Util . escapeMarkdown ( video . title ) ,
url : ` https://www.youtube.com/watch?v= ${ video . id } `
} ;
if ( ! serverQueue ) {
const queueConstruct = {
textChannel : msg . channel ,
voiceChannel : voiceChannel ,
connection : null ,
songs : [ ] ,
volume : 5 ,
playing : true
} ;
queue . set ( msg . guild . id , queueConstruct ) ;
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
queueConstruct . songs . push ( song ) ;
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
try {
var connection = await voiceChannel . join ( ) ;
queueConstruct . connection = connection ;
play ( msg . guild , queueConstruct . songs [ 0 ] ) ;
} catch ( error ) {
2019-07-10 10:11:50 +00:00
console . error ( ` I could not join the voice channel: ${ error } ` ) ;
2019-05-30 09:01:25 +00:00
queue . delete ( msg . guild . id ) ;
return msg . channel . send ( ` :x: I could not join the voice channel: ${ error } ` ) ;
}
} else {
serverQueue . songs . push ( song ) ;
if ( playlist ) return undefined ;
else return msg . channel . send ( ` :white_check_mark: ** ${ song . title } ** has been added to the queue! ` ) ;
}
return undefined ;
}
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
function play ( guild , song ) {
const serverQueue = queue . get ( guild . id ) ;
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
if ( ! song ) {
serverQueue . voiceChannel . leave ( ) ;
queue . delete ( guild . id ) ;
return ;
}
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
const dispatcher = serverQueue . connection . playStream ( ytdl ( song . url , { quality : ` highestaudio ` , filter : 'audioonly' } ) )
. on ( 'end' , reason => {
2019-07-10 10:11:50 +00:00
if ( reason === 'Stream is not generating quickly enough.' ) console . log ( 'Song ended.' ) ;
2019-07-12 06:47:28 +00:00
else console . log ( reason ) ;
2019-05-30 09:01:25 +00:00
serverQueue . songs . shift ( ) ;
play ( guild , serverQueue . songs [ 0 ] ) ;
} )
2019-07-10 10:11:50 +00:00
. on ( 'error' , error => console . error ( error ) ) ;
2019-05-31 18:38:53 +00:00
dispatcher . setVolumeLogarithmic ( 1 / 5 ) ;
2019-05-31 18:43:07 +00:00
serverQueue . volume = 1
2019-07-10 10:11:50 +00:00
2019-05-30 09:01:25 +00:00
serverQueue . textChannel . send ( ` :musical_note: Start playing: ** ${ song . title } ** ` ) ;
}
2019-07-10 10:11:50 +00:00
2019-07-10 10:13:24 +00:00
client . login ( process . env . BOT _TOKEN ) ;