2018-10-29 15:28:58 +01:00
package nl.voidcorp.dbot.music
2018-10-14 14:16:14 +02:00
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist
import com.sedmelluq.discord.lavaplayer.track.AudioTrack
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame
import net.dv8tion.jda.core.audio.AudioSendHandler
2018-10-15 22:25:51 +02:00
import nl.voidcorp.dbot.addAll
import nl.voidcorp.dbot.commands
2018-11-06 22:46:53 +01:00
import nl.voidcorp.dbot.commands.*
2018-10-14 14:16:14 +02:00
import nl.voidcorp.dbot.log
import nl.voidcorp.dbot.playerManager
val guildMusicMap = mutableMapOf < Long , TrackScheduler > ( )
fun initMusic ( ) {
AudioSourceManagers . registerRemoteSources ( playerManager )
2018-10-30 20:38:44 +01:00
val queueCommand = UnityMusicCommand (
2018-11-05 22:10:19 +01:00
" play " ,
aliases = mutableListOf ( " p " , " queue " , " q " ) ,
2018-10-30 20:38:44 +01:00
help = " Use this command to queue a song, if you don't add a link it will search on youtube with the specified arguments \n \n Execute with no arguments to view the current queue! " ,
howTo = " q [link] "
) { event , scheduler ->
2018-10-14 14:16:14 +02:00
2018-10-15 22:25:51 +02:00
if ( event . args . isEmpty ( ) ) {
if ( ! guildMusicMap . containsKey ( event . guild . idLong ) || ( guildMusicMap [ event . guild . idLong ] !! . player . playingTrack == null ) )
event . reply ( " The track list is empty " ) else
event . reply ( guildMusicMap [ event . guild . idLong ] !! . getTrackList ( event . member ) )
2018-10-17 21:15:09 +02:00
return @UnityMusicCommand
2018-10-15 22:25:51 +02:00
}
2018-10-14 14:16:14 +02:00
playerManager . loadItem ( event . args , object : AudioLoadResultHandler {
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
override fun trackLoaded ( track : AudioTrack ) {
scheduler . queue ( track , event . member )
}
override fun noMatches ( ) {
2018-10-14 22:20:47 +02:00
getLinkFromSearch ( event , scheduler , false )
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
for ( t in playlist . tracks ) {
scheduler . queue ( t , event . member )
}
}
} )
}
2018-10-30 20:38:44 +01:00
val ytCommand = UnityMusicCommand (
" youtube " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " yt " ) ,
2018-10-30 20:38:44 +01:00
help = " Search YouTube for a song! " ,
howTo = " youtube <search term or link> "
) { event , scheduler ->
2018-10-17 21:15:09 +02:00
if ( event . args . isEmpty ( ) ) {
2018-11-07 23:25:56 +01:00
event . reply ( " Please supply a song title or URL! " )
2018-10-17 21:15:09 +02:00
return @UnityMusicCommand
}
playerManager . loadItem ( event . args , object : AudioLoadResultHandler {
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
override fun trackLoaded ( track : AudioTrack ) {
scheduler . queue ( track , event . member )
}
override fun noMatches ( ) {
getLinkFromSearch ( event , scheduler , false )
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
for ( t in playlist . tracks ) {
scheduler . queue ( t , event . member )
}
}
} )
2018-10-14 22:20:47 +02:00
}
2018-10-30 20:38:44 +01:00
val soundcloudCommand = UnityMusicCommand (
" soundcloud " ,
help = " Play a song via SoundCloud! " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " sc " ) ,
2018-10-30 20:38:44 +01:00
howTo = " sc <link or search term> "
) { event , scheduler ->
2018-10-17 21:15:09 +02:00
if ( event . args . isEmpty ( ) ) {
2018-11-07 23:25:56 +01:00
event . reply ( " Please supply a song title or URL! " )
2018-10-17 21:15:09 +02:00
return @UnityMusicCommand
}
2018-10-14 22:20:47 +02:00
playerManager . loadItem ( event . args , object : AudioLoadResultHandler {
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
override fun trackLoaded ( track : AudioTrack ) {
scheduler . queue ( track , event . member )
}
override fun noMatches ( ) {
getLinkFromSearch ( event , scheduler , false , " scsearch " )
2018-10-14 14:16:14 +02:00
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
for ( t in playlist . tracks ) {
scheduler . queue ( t , event . member )
}
}
} )
}
2018-10-30 20:38:44 +01:00
val playCommand = UnityMusicCommand (
2018-11-05 22:10:19 +01:00
" fplay " ,
2018-10-30 20:38:44 +01:00
" Force this song to be the next! " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " fp " ) ,
2018-10-30 20:38:44 +01:00
howTo = " play <url> " ,
category = MusicCategoryPrivate
) { event , scheduler ->
2018-10-17 21:15:09 +02:00
if ( event . args . isEmpty ( ) ) {
2018-11-07 23:25:56 +01:00
event . reply ( " Please supply a song title or URL! " )
2018-10-17 21:15:09 +02:00
return @UnityMusicCommand
}
2018-10-14 14:16:14 +02:00
playerManager . loadItem ( event . args , object : AudioLoadResultHandler {
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
override fun trackLoaded ( track : AudioTrack ) {
scheduler . insertFront ( track , event . member )
2018-11-05 22:10:19 +01:00
if ( ! scheduler . isQueueEmpty ( ) )
scheduler . skip ( )
2018-10-14 14:16:14 +02:00
}
override fun noMatches ( ) {
2018-10-14 22:20:47 +02:00
getLinkFromSearch ( event , scheduler , true )
2018-10-14 14:16:14 +02:00
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
for ( t in playlist . tracks ) {
scheduler . insertFront ( t , event . member )
}
}
} )
}
2018-10-14 22:20:47 +02:00
2018-10-30 20:38:44 +01:00
val skipCommand = UnityCommand (
2018-11-05 17:41:18 +01:00
" fskip " ,
help = " Force skips the current song, admin only " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " fs " , " ffs " ) ,
2018-11-05 17:41:18 +01:00
category = MusicCategoryPrivate
2018-10-30 20:38:44 +01:00
) { event ->
2018-10-14 14:16:14 +02:00
val scheduler = guildMusicMap [ event . guild . idLong ]
if ( scheduler == null ) {
event . reply ( " There is no music playing? " )
} else {
scheduler . skip ( )
}
2018-10-15 22:25:51 +02:00
}
2018-11-05 17:41:18 +01:00
val voteSkipCommand = UnityMusicCommand (
" vskip " ,
help = " Starts a vote to skip the current song " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " voteskip " , " skip " , " vs " , " s " )
2018-11-05 17:41:18 +01:00
) { event , scheduler ->
val ss = scheduler . shouldSkip ( )
if ( ss ) {
event . reply ( " Vote passed, skipping song! " )
scheduler . skip ( )
} else {
event . reply ( " Vote registered! " )
}
}
2018-10-30 20:38:44 +01:00
val npCommand = UnityMusicCommand (
" nowplaying " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " np " ) ,
2018-10-30 20:38:44 +01:00
help = " Show the currently playing song "
) { event , scheduler ->
2018-10-15 22:25:51 +02:00
if ( ! scheduler . isSongPlaying ( ) ) {
event . reply ( " There is no song playing? " )
} else {
event . reply ( scheduler . getCurrentTrackInfo ( ) )
}
}
2018-10-30 20:38:44 +01:00
val attachmentPlay = UnityMusicCommand (
" attachment " ,
help = " Play any attached song, if it is in a normal format that is... \n \n `just drag and drop the song on your Discord window and in the optional comment add !attach(ment)` " ,
2018-11-05 22:10:19 +01:00
aliases = mutableListOf ( " attach " )
2018-10-30 20:38:44 +01:00
) { event , scheduler ->
2018-10-15 22:25:51 +02:00
val attach = event . message . attachments . firstOrNull ( )
if ( attach == null ) {
event . reply ( " I can't play an attachment without an attachment... " )
} else {
playerManager . loadItem ( attach . url , object : AudioLoadResultHandler {
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
2018-10-14 14:16:14 +02:00
2018-10-15 22:25:51 +02:00
override fun trackLoaded ( track : AudioTrack ) {
scheduler . queue ( track , event . member )
if ( ! scheduler . isQueueEmpty ( ) or scheduler . isSongPlaying ( ) ) {
scheduler . getTrackInfo ( track )
}
}
override fun noMatches ( ) {
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
for ( t in playlist . tracks ) {
scheduler . queue ( t , event . member )
}
}
} )
}
2018-10-14 14:16:14 +02:00
}
2018-11-06 22:46:53 +01:00
val loopCommand =
UnityMusicCommand ( " loop " , " Loops the queue! \n Or disables it! " , MusicCategory ) { event , scheduler ->
if ( scheduler . loop ) {
event . reply ( " The queue will no longer loop! " )
} else {
event . reply ( " The queue wil now loop " )
}
scheduler . loop = ! scheduler . loop
}
val stopCommand = UnityMusicCommand (
" stop " ,
" Stops this shit! " ,
MusicCategoryPrivate ,
aliases = mutableListOf ( )
) { event , scheduler ->
scheduler . clearQueue ( )
event . reply ( " Stopped all playback! " )
}
2018-10-14 14:16:14 +02:00
2018-11-05 17:41:18 +01:00
commands . addAll (
playCommand ,
skipCommand ,
queueCommand ,
ytCommand ,
soundcloudCommand ,
npCommand ,
attachmentPlay ,
2018-11-06 22:46:53 +01:00
voteSkipCommand ,
loopCommand ,
stopCommand
2018-11-05 17:41:18 +01:00
)
2018-10-14 14:16:14 +02:00
}
2018-10-30 20:38:44 +01:00
fun getLinkFromSearch (
event : UnityCommandEvent ,
scheduler : TrackScheduler ,
shouldInsertFront : Boolean ,
searchPrefix : String = " ytsearch "
) {
2018-10-14 22:20:47 +02:00
log . info ( " Searching youtube for ' ${event.args} ' " )
2018-10-14 14:16:14 +02:00
2018-10-14 22:20:47 +02:00
playerManager . loadItem ( " $searchPrefix : ${event.args} " , object : AudioLoadResultHandler {
2018-10-14 14:16:14 +02:00
override fun loadFailed ( exception : FriendlyException ) {
event . reply ( " Shit's fucked! " )
}
override fun trackLoaded ( track : AudioTrack ) {
2018-11-05 22:10:19 +01:00
if ( shouldInsertFront ) {
2018-10-14 22:20:47 +02:00
scheduler . insertFront ( track , event . member )
2018-11-05 22:10:19 +01:00
if ( ! scheduler . isQueueEmpty ( ) )
scheduler . skip ( )
2018-11-06 22:46:53 +01:00
} else
2018-10-14 22:20:47 +02:00
scheduler . queue ( track , event . member )
2018-10-14 14:16:14 +02:00
/ * event . reply (
EmbedBuilder ( ) . setImage ( r . snippet . thumbnails . high . url ) . setTitle ( r . snippet . title , " https://youtu.be/ $id " )
. setAuthor ( r . snippet . channelTitle ) . setFooter ( " Requested by ${event.member.effectiveName} " , event . author . effectiveAvatarUrl )
. setDescription ( r . snippet . description ) . build ( )
) * /
}
override fun noMatches ( ) {
}
override fun playlistLoaded ( playlist : AudioPlaylist ) {
if ( ! playlist . isSearchResult )
for ( t in playlist . tracks ) {
2018-11-05 22:10:19 +01:00
if ( shouldInsertFront ) {
2018-10-14 22:20:47 +02:00
scheduler . insertFront ( t , event . member )
2018-11-05 22:10:19 +01:00
if ( ! scheduler . isQueueEmpty ( ) )
scheduler . skip ( )
} else
2018-10-14 22:20:47 +02:00
scheduler . queue ( t , event . member )
2018-10-14 14:16:14 +02:00
}
else {
val track = playlist . tracks . first ( )
2018-10-14 22:20:47 +02:00
2018-10-14 14:16:14 +02:00
2018-10-14 22:20:47 +02:00
if ( shouldInsertFront )
scheduler . insertFront ( track , event . member )
else
scheduler . queue ( track , event . member )
2018-10-14 14:16:14 +02:00
2018-10-15 22:25:51 +02:00
if ( ! scheduler . isQueueEmpty ( ) or scheduler . isSongPlaying ( ) ) {
if ( scheduler . player . playingTrack != track )
event . reply ( scheduler . getTrackInfo ( track ) )
}
2018-10-14 14:16:14 +02:00
}
}
} )
}
class AudioPlayerSendHandler ( private val audioPlayer : AudioPlayer ) : AudioSendHandler {
private var lastFrame : AudioFrame ? = null
override fun canProvide ( ) : Boolean {
lastFrame = audioPlayer . provide ( )
return lastFrame != null
}
override fun provide20MsAudio ( ) : ByteArray {
return lastFrame !! . data
}
override fun isOpus ( ) : Boolean {
return true
}
}