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() 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 ") { 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 ") { 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 ", 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 } }