280 lines
9.6 KiB
Kotlin
280 lines
9.6 KiB
Kotlin
package nl.voidcorp.dbot.music
|
|
|
|
import com.jagrosh.jdautilities.command.CommandEvent
|
|
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
|
|
import nl.voidcorp.dbot.addAll
|
|
import nl.voidcorp.dbot.commands
|
|
import nl.voidcorp.dbot.commands.UnityCommand
|
|
import nl.voidcorp.dbot.commands.UnityMusicCommand
|
|
import nl.voidcorp.dbot.commands.MusicCategory
|
|
import nl.voidcorp.dbot.commands.MusicCategoryPrivate
|
|
import nl.voidcorp.dbot.log
|
|
import nl.voidcorp.dbot.playerManager
|
|
|
|
|
|
val guildMusicMap = mutableMapOf<Long, TrackScheduler>()
|
|
|
|
fun initMusic() {
|
|
AudioSourceManagers.registerRemoteSources(playerManager)
|
|
|
|
|
|
val queueCommand = UnityMusicCommand("queue", aliases = *arrayOf("q"), 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\nExecute with no arguments to view the current queue!", howTo = "q [link]") { event, scheduler ->
|
|
|
|
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))
|
|
|
|
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)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
val ytCommand = UnityMusicCommand("youtube", aliases = *arrayOf("yt"), help = "Search YouTube for a song!", howTo = "youtube <search term or link>") { event, scheduler ->
|
|
if (event.args.isEmpty()) {
|
|
event.reply("Please supply a song name or URL!")
|
|
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)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
val soundcloudCommand = UnityMusicCommand("soundcloud", help = "Play a song via SoundCloud!", aliases = *arrayOf("sc"), howTo = "sc <link or search term>") { event, scheduler ->
|
|
if (event.args.isEmpty()) {
|
|
event.reply("Please supply a song name or URL!")
|
|
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, "scsearch")
|
|
}
|
|
|
|
override fun playlistLoaded(playlist: AudioPlaylist) {
|
|
for (t in playlist.tracks) {
|
|
scheduler.queue(t, event.member)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
val playCommand = UnityMusicCommand("play", "Force this song to be the next!", aliases = *arrayOf("p"), howTo = "play <url>", category = MusicCategoryPrivate) { event, scheduler ->
|
|
if (event.args.isEmpty()) {
|
|
event.reply("Please supply a song name or URL!")
|
|
return@UnityMusicCommand
|
|
}
|
|
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)
|
|
}
|
|
|
|
override fun noMatches() {
|
|
getLinkFromSearch(event, scheduler, true)
|
|
}
|
|
|
|
override fun playlistLoaded(playlist: AudioPlaylist) {
|
|
for (t in playlist.tracks) {
|
|
scheduler.insertFront(t, event.member)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
|
|
val skipCommand = UnityCommand("skip", help = "Skip the current song", aliases = *arrayOf("s"), category = MusicCategory) { event ->
|
|
val scheduler = guildMusicMap[event.guild.idLong]
|
|
if (scheduler == null) {
|
|
event.reply("There is no music playing?")
|
|
} else {
|
|
scheduler.skip()
|
|
}
|
|
}
|
|
|
|
val npCommand = UnityMusicCommand("nowplaying", aliases = *arrayOf("np"), help = "Show the currently playing song") { event, scheduler ->
|
|
if (!scheduler.isSongPlaying()) {
|
|
event.reply("There is no song playing?")
|
|
} else {
|
|
event.reply(scheduler.getCurrentTrackInfo())
|
|
}
|
|
}
|
|
|
|
|
|
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)`", aliases = *arrayOf("attach")) { event, scheduler ->
|
|
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!")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
|
|
commands.addAll(playCommand, skipCommand, queueCommand, ytCommand, soundcloudCommand, npCommand, attachmentPlay)
|
|
}
|
|
|
|
fun getLinkFromSearch(event: CommandEvent, scheduler: TrackScheduler, shouldInsertFront: Boolean, searchPrefix: String = "ytsearch") {
|
|
log.info("Searching youtube for '${event.args}'")
|
|
|
|
playerManager.loadItem("$searchPrefix:${event.args}", object : AudioLoadResultHandler {
|
|
override fun loadFailed(exception: FriendlyException) {
|
|
event.reply("Shit's fucked!")
|
|
}
|
|
|
|
override fun trackLoaded(track: AudioTrack) {
|
|
if (shouldInsertFront)
|
|
scheduler.insertFront(track, event.member)
|
|
else
|
|
scheduler.queue(track, event.member)
|
|
/*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) {
|
|
if (shouldInsertFront)
|
|
scheduler.insertFront(t, event.member)
|
|
else
|
|
scheduler.queue(t, event.member)
|
|
}
|
|
else {
|
|
val track = playlist.tracks.first()
|
|
|
|
|
|
|
|
|
|
if (shouldInsertFront)
|
|
scheduler.insertFront(track, event.member)
|
|
else
|
|
scheduler.queue(track, event.member)
|
|
|
|
if (!scheduler.isQueueEmpty() or scheduler.isSongPlaying()) {
|
|
if (scheduler.player.playingTrack != track)
|
|
event.reply(scheduler.getTrackInfo(track))
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
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
|
|
}
|
|
} |