From 68aadceb4034d37bf70a0aa7def99083d5a0ea33 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 29 Mar 2022 12:59:26 -0700 Subject: [PATCH] Audio/Music Prep --- src/main/java/moe/oko/Kiafumi/Kiafumi.java | 16 ++++ .../oko/Kiafumi/model/audio/AudioInfo.java | 47 ++++++++++ .../model/audio/AudioPlayerSendHandler.java | 37 ++++++++ .../oko/Kiafumi/model/audio/TrackManager.java | 89 +++++++++++++++++++ .../moe/oko/Kiafumi/util/CommandInfo.java | 4 + 5 files changed, 193 insertions(+) create mode 100644 src/main/java/moe/oko/Kiafumi/model/audio/AudioInfo.java create mode 100644 src/main/java/moe/oko/Kiafumi/model/audio/AudioPlayerSendHandler.java create mode 100644 src/main/java/moe/oko/Kiafumi/model/audio/TrackManager.java diff --git a/src/main/java/moe/oko/Kiafumi/Kiafumi.java b/src/main/java/moe/oko/Kiafumi/Kiafumi.java index 0eeb2be..d9fbd8c 100644 --- a/src/main/java/moe/oko/Kiafumi/Kiafumi.java +++ b/src/main/java/moe/oko/Kiafumi/Kiafumi.java @@ -24,6 +24,7 @@ import org.simpleyaml.configuration.file.YamlConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.awt.*; import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; @@ -143,6 +144,13 @@ public class Kiafumi { * Ran on program shutdown. */ public void stop() { + EmbedBuilder build = new EmbedBuilder() + .setColor(EmbedUI.FAILURE) + .setFooter(EmbedUI.BRAND) + .setTimestamp(ZonedDateTime.now()) + .setTitle("Offline") + .setDescription("Shutdown SIGINT Received."); + JDA.getTextChannelById(config.getLogChannel()).sendMessageEmbeds(build.build()).queue(); if(database.saveServerInformation()) { info("Successfully saved server information. Shutting down peacefully."); } else { @@ -188,10 +196,12 @@ public class Kiafumi { * Quick method to register commands in all servers. */ private void registerAllCommands() { + //Registers our slash commands for(Guild guild : JDA.getGuilds()) { registerForGuild(guild); } + //Registers the event listeners for those commands. for(CommandClass cmd : activeCommands) { JDA.addEventListener(cmd); } @@ -202,13 +212,16 @@ public class Kiafumi { * @param guild - guild to have commands provided to */ public void registerForGuild(Guild guild) { + info("Standby for command strip on guild " + guild.getId()); info("Registering commands for " + guild.getId()); int i = 0; for(CommandClass cmd : activeCommands) { for(CommandInfo ci : cmd.getSlashCommandInfo()) { + info("Registering Command: " + ci.getName()); CommandCreateAction cca = guild.upsertCommand(ci.getName(), ci.getDescription()); i++; if(ci.hasSubCommands()) { + info("Command has sub-commands."); for (String name : ci.getSubCommands().keySet()) { CommandInfo si = ci.getSubCommands().get(name); SubcommandData sd = new SubcommandData(si.getName(), si.getDescription()); @@ -216,15 +229,18 @@ public class Kiafumi { sd.addOption(si.getOptions().get(option), option, si.getOptionDescriptions().get(option), si.getOptionRequirements().get(option)); } cca.addSubcommands(sd); + info("Added subcommand: " + name); } } if(ci.hasOptions()) { + info("Command has options."); for(String name : ci.getOptions().keySet()) { //Any intelligent IDE will rage about the option not being used, it's added to the action then executed later, DO not edit this (please). cca.addOption(ci.getOptions().get(name), name, ci.getOptionDescriptions().get(name), ci.getOptionRequirements().get(name)); } } //Push w/ modifications. + info("Command: " + ci.getName() + " registration on " + guild.getId() + " completed."); cca.queue(); } } diff --git a/src/main/java/moe/oko/Kiafumi/model/audio/AudioInfo.java b/src/main/java/moe/oko/Kiafumi/model/audio/AudioInfo.java new file mode 100644 index 0000000..cc994e4 --- /dev/null +++ b/src/main/java/moe/oko/Kiafumi/model/audio/AudioInfo.java @@ -0,0 +1,47 @@ +package moe.oko.Kiafumi.model.audio; + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.User; + +import java.util.HashSet; +import java.util.Set; + +/** + * Imported from SHIRO project. + * License for Kiafumi still applies. + * @author Kay + */ +public class AudioInfo { + + private final AudioTrack track; + private final Set skips; + private final Member author; + + AudioInfo(AudioTrack track, Member author) { + this.track = track; + this.skips = new HashSet<>(); + this.author = author; + } + + public AudioTrack getTrack() { + return track; + } + + public int getSkips() { + return skips.size(); + } + + public void addSkip(User u) { + skips.add(u.getId()); + } + + public boolean hasVoted(User u) { + return skips.contains(u.getId()); + } + + public Member getAuthor() { + return author; + } + +} diff --git a/src/main/java/moe/oko/Kiafumi/model/audio/AudioPlayerSendHandler.java b/src/main/java/moe/oko/Kiafumi/model/audio/AudioPlayerSendHandler.java new file mode 100644 index 0000000..8989f02 --- /dev/null +++ b/src/main/java/moe/oko/Kiafumi/model/audio/AudioPlayerSendHandler.java @@ -0,0 +1,37 @@ +package moe.oko.Kiafumi.model.audio; + +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; + +/** + * Imported from SHIRO project. + * License for Kiafumi still applies + * @author Kay + */ +public class AudioPlayerSendHandler implements AudioSendHandler { + private final AudioPlayer audioPlayer; + private AudioFrame lastFrame; + + public AudioPlayerSendHandler(AudioPlayer audioPlayer) { + this.audioPlayer = audioPlayer; + } + + @Override + public boolean canProvide() { + lastFrame = audioPlayer.provide(); + return lastFrame != null; + } + + @Override + public ByteBuffer provide20MsAudio() { + return ByteBuffer.wrap(lastFrame.getData()); + } + + @Override + public boolean isOpus() { + return true; + } +} diff --git a/src/main/java/moe/oko/Kiafumi/model/audio/TrackManager.java b/src/main/java/moe/oko/Kiafumi/model/audio/TrackManager.java new file mode 100644 index 0000000..820da2a --- /dev/null +++ b/src/main/java/moe/oko/Kiafumi/model/audio/TrackManager.java @@ -0,0 +1,89 @@ +package moe.oko.Kiafumi.model.audio; + +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 net.dv8tion.jda.api.entities.AudioChannel; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; + +import java.util.*; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Import from SHIRO project. + * License for Kiafumi still applies + * @author Kay + */ +public class TrackManager extends AudioEventAdapter { + + private final AudioPlayer player; + private final Queue queue; + + public TrackManager(AudioPlayer player) { + this.player = player; + this.queue = new LinkedBlockingQueue<>(); + } + + /** + * Queues a new track to be played. + * @param track - the track to be played + * @param author - the person who queued the track + */ + public void queue(AudioTrack track, Member author) { + AudioInfo info = new AudioInfo(track, author); + queue.add(info); + + if (player.getPlayingTrack() == null) { + player.playTrack(track); + } + } + + @Override + public void onTrackStart(AudioPlayer player, AudioTrack track) { + AudioInfo info = queue.element(); + AudioChannel vChan = info.getAuthor().getVoiceState().getChannel(); + if (vChan == null) { // User has left all voice channels + player.stopTrack(); + } else { + info.getAuthor().getGuild().getAudioManager().openAudioConnection(vChan); + } + } + + @Override + public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { + Guild g = queue.poll().getAuthor().getGuild(); + if (queue.isEmpty()) { + g.getAudioManager().closeAudioConnection(); + } else { + player.playTrack(queue.element().getTrack()); + } + } + + public void shuffleQueue() { + List tQueue = new ArrayList<>(getQueuedTracks()); + AudioInfo current = tQueue.get(0); + tQueue.remove(0); + Collections.shuffle(tQueue); + tQueue.add(0, current); + purgeQueue(); + queue.addAll(tQueue); + } + + public Set getQueuedTracks() { + return new LinkedHashSet<>(queue); + } + + public void purgeQueue() { + queue.clear(); + } + + public void remove(AudioInfo entry) { + queue.remove(entry); + } + + public AudioInfo getTrackInfo(AudioTrack track) { + return queue.stream().filter(audioInfo -> audioInfo.getTrack().equals(track)).findFirst().orElse(null); + } +} diff --git a/src/main/java/moe/oko/Kiafumi/util/CommandInfo.java b/src/main/java/moe/oko/Kiafumi/util/CommandInfo.java index edb0f3d..df38554 100644 --- a/src/main/java/moe/oko/Kiafumi/util/CommandInfo.java +++ b/src/main/java/moe/oko/Kiafumi/util/CommandInfo.java @@ -78,6 +78,10 @@ public class CommandInfo { optionRequirements.put(name, required); } + /** + * The way you add subcommands to a command. NOTE you cannot have options for the command if you use this. + * @param cmdInfo - The CommandInfo for the subcommand (including options). + */ public void addSubcommand(CommandInfo cmdInfo) { subCommands.put(cmdInfo.name, cmdInfo); }