From faab0c818ca23494b8d785dcc723752fa097e803 Mon Sep 17 00:00:00 2001 From: Julius de Jeu Date: Mon, 27 May 2019 23:06:45 +0200 Subject: [PATCH] Woo, audio! Added a basic play command, which for now just loads a totally random video. Also added a kill command to forcefully stop a connection, might move that to debug --- build.gradle | 1 + src/main/kotlin/nl/voidcorp/discord/Loader.kt | 10 +++++-- .../voidcorp/discord/command/CommandGroup.kt | 1 + .../discord/commands/music/ForceLeave.kt | 17 +++++++++++ .../voidcorp/discord/commands/music/Play.kt | 28 +++++++++++++++++ .../discord/music/AudioLoadHandler.kt | 30 +++++++++++++++++++ .../discord/music/AudioPlayerSendHandler.kt | 22 ++++++++++++++ .../voidcorp/discord/music/PlayerManager.kt | 22 ++++++++++++++ .../voidcorp/discord/music/TrackScheduler.kt | 25 ++++++++++++++++ 9 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/nl/voidcorp/discord/commands/music/ForceLeave.kt create mode 100644 src/main/kotlin/nl/voidcorp/discord/commands/music/Play.kt create mode 100644 src/main/kotlin/nl/voidcorp/discord/music/AudioLoadHandler.kt create mode 100644 src/main/kotlin/nl/voidcorp/discord/music/AudioPlayerSendHandler.kt create mode 100644 src/main/kotlin/nl/voidcorp/discord/music/PlayerManager.kt create mode 100644 src/main/kotlin/nl/voidcorp/discord/music/TrackScheduler.kt diff --git a/build.gradle b/build.gradle index 508b716..bd9428a 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,7 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter:5.4.2" implementation 'net.dv8tion:JDA:4.ALPHA.0_88' + implementation 'com.sedmelluq:lavaplayer:1.3.17' implementation "com.h2database:h2" diff --git a/src/main/kotlin/nl/voidcorp/discord/Loader.kt b/src/main/kotlin/nl/voidcorp/discord/Loader.kt index 7cfdbbd..adbf09a 100644 --- a/src/main/kotlin/nl/voidcorp/discord/Loader.kt +++ b/src/main/kotlin/nl/voidcorp/discord/Loader.kt @@ -1,12 +1,15 @@ package nl.voidcorp.discord +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager +import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder import nl.voidcorp.discord.events.CommandListener import nl.voidcorp.discord.events.OttoListener -import org.springframework.stereotype.Component +import org.springframework.stereotype.Service -@Component -class Loader(listener: CommandListener) { + +@Service +class Loader(listener: CommandListener, playerManager: DefaultAudioPlayerManager) { init { val token = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("'DISCORD_TOKEN' not set!") val builder = DefaultShardManagerBuilder(token) @@ -16,5 +19,6 @@ class Loader(listener: CommandListener) { builder.addEventListeners(OttoListener, listener) jda = builder.build() + AudioSourceManagers.registerRemoteSources(playerManager) } } \ No newline at end of file diff --git a/src/main/kotlin/nl/voidcorp/discord/command/CommandGroup.kt b/src/main/kotlin/nl/voidcorp/discord/command/CommandGroup.kt index 8829c47..c4c4b6a 100644 --- a/src/main/kotlin/nl/voidcorp/discord/command/CommandGroup.kt +++ b/src/main/kotlin/nl/voidcorp/discord/command/CommandGroup.kt @@ -3,6 +3,7 @@ package nl.voidcorp.discord.command enum class CommandGroup { GENERAL, FUN, + MUSIC, ROLES, ADMIN, VeRY_hIdden_CaTegoRY_LoL, diff --git a/src/main/kotlin/nl/voidcorp/discord/commands/music/ForceLeave.kt b/src/main/kotlin/nl/voidcorp/discord/commands/music/ForceLeave.kt new file mode 100644 index 0000000..4d0ff51 --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/commands/music/ForceLeave.kt @@ -0,0 +1,17 @@ +package nl.voidcorp.discord.commands.music + +import nl.voidcorp.discord.command.* +import org.springframework.stereotype.Service + +@Service +class ForceLeave : Command( + "forceleave", + group = CommandGroup.MUSIC, + location = CommandSource.GUILD, + commandLevel = CommandLevel.MODERATOR +) { + override fun handle(event: CommandMessage): CommandResult { + event.guild!!.audioManager.closeAudioConnection() + return CommandResult.SUCCESS + } +} \ No newline at end of file diff --git a/src/main/kotlin/nl/voidcorp/discord/commands/music/Play.kt b/src/main/kotlin/nl/voidcorp/discord/commands/music/Play.kt new file mode 100644 index 0000000..6d671e6 --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/commands/music/Play.kt @@ -0,0 +1,28 @@ +package nl.voidcorp.discord.commands.music + +import nl.voidcorp.discord.command.* +import nl.voidcorp.discord.music.AudioLoadHandler +import nl.voidcorp.discord.music.PlayerManager +import org.springframework.stereotype.Service + +@Service +class Play(val playerManager: PlayerManager) : + Command("play", location = CommandSource.GUILD, group = CommandGroup.MUSIC) { + override fun handle(event: CommandMessage): CommandResult { + val chan = event.member!!.voiceState!!.channel + if (chan == null) { + event.reply("Please join a voice channel to play music!") + return CommandResult.SUCCESS + } + val am = event.guild!!.audioManager + + am.openAudioConnection(chan) + + val ts = playerManager.getGuildPlayer(event.guild) + + playerManager.loadItem("https://www.youtube.com/watch?v=kPgiJUeSP6Q", AudioLoadHandler(ts)) + + + return CommandResult.SUCCESS + } +} \ No newline at end of file diff --git a/src/main/kotlin/nl/voidcorp/discord/music/AudioLoadHandler.kt b/src/main/kotlin/nl/voidcorp/discord/music/AudioLoadHandler.kt new file mode 100644 index 0000000..a25cfb3 --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/music/AudioLoadHandler.kt @@ -0,0 +1,30 @@ +package nl.voidcorp.discord.music + +import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler +import com.sedmelluq.discord.lavaplayer.tools.FriendlyException +import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist +import com.sedmelluq.discord.lavaplayer.track.AudioTrack +import nl.voidcorp.discord.logger + + +class AudioLoadHandler(private val trackScheduler: TrackScheduler) : AudioLoadResultHandler { + + override fun loadFailed(exception: FriendlyException) { + throw exception + } + + override fun trackLoaded(track: AudioTrack) { + logger.info("loaded track ${track.identifier}") + trackScheduler.queue(track) + } + + override fun noMatches() { + + } + + override fun playlistLoaded(playlist: AudioPlaylist) { + for (t in playlist.tracks) { + trackScheduler.queue(t) + } + } +} diff --git a/src/main/kotlin/nl/voidcorp/discord/music/AudioPlayerSendHandler.kt b/src/main/kotlin/nl/voidcorp/discord/music/AudioPlayerSendHandler.kt new file mode 100644 index 0000000..81d455e --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/music/AudioPlayerSendHandler.kt @@ -0,0 +1,22 @@ +package nl.voidcorp.discord.music + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer +import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame +import net.dv8tion.jda.api.audio.AudioSendHandler +import java.nio.ByteBuffer + + +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() = ByteBuffer.wrap(lastFrame!!.data) + + override fun isOpus(): Boolean { + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/nl/voidcorp/discord/music/PlayerManager.kt b/src/main/kotlin/nl/voidcorp/discord/music/PlayerManager.kt new file mode 100644 index 0000000..3771047 --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/music/PlayerManager.kt @@ -0,0 +1,22 @@ +package nl.voidcorp.discord.music + +import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager +import net.dv8tion.jda.api.entities.Guild +import org.springframework.stereotype.Service + +@Service +class PlayerManager : DefaultAudioPlayerManager() { + val guildPlayMap = mutableMapOf() + fun getGuildPlayer(guild: Guild): TrackScheduler { + return if (guildPlayMap.containsKey(guild.idLong)) { + guildPlayMap[guild.idLong] ?: error("oof?") + } else { + val player = createPlayer() + val ts = TrackScheduler(player) + player.addListener(ts) + guild.audioManager.sendingHandler = AudioPlayerSendHandler(player) + guildPlayMap[guild.idLong] = ts + ts + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/nl/voidcorp/discord/music/TrackScheduler.kt b/src/main/kotlin/nl/voidcorp/discord/music/TrackScheduler.kt new file mode 100644 index 0000000..4b25d75 --- /dev/null +++ b/src/main/kotlin/nl/voidcorp/discord/music/TrackScheduler.kt @@ -0,0 +1,25 @@ +package nl.voidcorp.discord.music + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer +import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter +import com.sedmelluq.discord.lavaplayer.track.AudioTrack +import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason +import java.util.* + +class TrackScheduler(private val player: AudioPlayer) : AudioEventAdapter() { + private val queue = ArrayDeque() + fun queue(track: AudioTrack) { + if (!player.startTrack(track, true)) { + queue.addLast(track) + } + + } + + fun pop() = queue.pop() + + override fun onTrackEnd(player: AudioPlayer, track: AudioTrack, endReason: AudioTrackEndReason) { + if (endReason.mayStartNext && queue.isNotEmpty()) { + player.startTrack(pop(), true) + } + } +} \ No newline at end of file