From 14952bf7912d5a6b704e677314e39369f349874c Mon Sep 17 00:00:00 2001 From: Benjamin Sherriff Date: Mon, 27 Mar 2023 21:41:37 -0400 Subject: [PATCH] v0.1.9 Cleanup and organization --- .gitignore | 3 +- Makefile | 5 +- docker-compose.yml | 2 +- pom.xml | 32 ++--- .../java/com/bensherriff/siren/MusicBot.java | 16 +-- .../bensherriff/siren/audio/AudioHandler.java | 27 ++-- .../siren/{listener => audio}/Listener.java | 136 +++++++++--------- .../siren/audio/PlayerManager.java | 1 - .../bensherriff/siren/commands/Command.java | 32 ++++- .../siren/commands/CommandEvent.java | 99 ------------- .../siren/commands/PauseCommand.java | 29 ++++ .../siren/commands/PlayCommand.java | 51 ++++--- .../siren/commands/ResumeCommand.java | 29 ++++ .../siren/commands/SkipCommand.java | 25 ++++ .../siren/commands/StopCommand.java | 26 ++++ .../siren/commands/VolumeCommand.java | 32 +++++ .../siren/listener/SlashListener.java | 132 ----------------- .../siren/listener/TextListener.java | 124 ---------------- src/main/resources/log4j2.xml | 28 +++- 19 files changed, 342 insertions(+), 487 deletions(-) rename src/main/java/com/bensherriff/siren/{listener => audio}/Listener.java (60%) delete mode 100644 src/main/java/com/bensherriff/siren/commands/CommandEvent.java create mode 100644 src/main/java/com/bensherriff/siren/commands/PauseCommand.java create mode 100644 src/main/java/com/bensherriff/siren/commands/ResumeCommand.java create mode 100644 src/main/java/com/bensherriff/siren/commands/SkipCommand.java create mode 100644 src/main/java/com/bensherriff/siren/commands/StopCommand.java create mode 100644 src/main/java/com/bensherriff/siren/commands/VolumeCommand.java delete mode 100644 src/main/java/com/bensherriff/siren/listener/SlashListener.java delete mode 100644 src/main/java/com/bensherriff/siren/listener/TextListener.java diff --git a/.gitignore b/.gitignore index 10c9d5b..f94094e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ **/target/ **/data/ -**/settings.json \ No newline at end of file +**/settings.json +**/logs/ \ No newline at end of file diff --git a/Makefile b/Makefile index ddaa989..f017364 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,13 @@ SHELL := /bin/bash build: - docker-compose build + docker rmi siren && docker-compose build test: docker run --rm -it siren:latest bash up: + if [[ "$(docker images -q siren 2> /dev/null)" == "" ]]; then docker-compose build; fi; \ docker-compose up -d down: @@ -15,3 +16,5 @@ down: exec: docker exec -it siren bash +clean: + docker rmi siren diff --git a/docker-compose.yml b/docker-compose.yml index 3356e83..62a6462 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: dockerfile: ./Dockerfile args: - JAVA_VERSION=17 - - VERSION=0.1.8 + - VERSION=0.1.9 volumes: - ./data:/app restart: unless-stopped diff --git a/pom.xml b/pom.xml index f1604b9..faae4f4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.bensherriff siren - 0.1.8 + 0.1.9 jar @@ -26,6 +26,11 @@ m2-dv8tion https://m2.dv8tion.net/releases + + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ + @@ -47,17 +52,17 @@ central ffc58a58b429-releases - http://repo.local.bensherriff.com/artifactory/libs-release + https://repo.local.bensherriff.com/artifactory/libs-release - 5.0.0-beta.3 - 1.3.77 + 5.0.0-beta.6 + 1.3.78 1.3.13 - 2.14.0 + 2.14.2 2.0.6 - 2.19.0 + 2.20.0 UTF-8 17 17 @@ -92,16 +97,6 @@ - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-simple - ${slf4j.version} - org.apache.logging.log4j log4j-api @@ -112,6 +107,11 @@ log4j-core ${log4j.version} + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + diff --git a/src/main/java/com/bensherriff/siren/MusicBot.java b/src/main/java/com/bensherriff/siren/MusicBot.java index 5ae549f..a28e164 100644 --- a/src/main/java/com/bensherriff/siren/MusicBot.java +++ b/src/main/java/com/bensherriff/siren/MusicBot.java @@ -1,20 +1,16 @@ package com.bensherriff.siren; -import com.bensherriff.siren.listener.Listener; -import com.bensherriff.siren.listener.SlashListener; -import com.bensherriff.siren.listener.TextListener; +import com.bensherriff.siren.audio.Listener; import com.bensherriff.siren.settings.Settings; import com.bensherriff.siren.settings.SettingsManager; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import javax.security.auth.login.LoginException; import java.io.IOException; import java.util.Arrays; @@ -41,8 +37,7 @@ public class MusicBot { private static void start() throws IOException { Settings settings = SettingsManager.load(); -// Listener textListener = new TextListener(settings); - Listener slashListener = new SlashListener(settings); + Listener listener = new Listener(settings); if (settings.getToken() == null || settings.getToken().isEmpty()) { throw new IOException("Token field may not be empty, please set the value in " + SettingsManager.PATH); @@ -54,12 +49,9 @@ public class MusicBot { .enableCache(Arrays.asList(ENABLED_FLAGS)) .disableCache(Arrays.asList(DISABLED_FLAGS)) .setActivity(Activity.playing("nothing")) - .setStatus(OnlineStatus.INVISIBLE) -// .addEventListeners(textListener) - .addEventListeners(slashListener) + .addEventListeners(listener) .setBulkDeleteSplittingEnabled(true) .build(); -// textListener.setJDA(jda); - slashListener.setJDA(jda); + listener.setJDA(jda); } } diff --git a/src/main/java/com/bensherriff/siren/audio/AudioHandler.java b/src/main/java/com/bensherriff/siren/audio/AudioHandler.java index c82934c..99438e6 100644 --- a/src/main/java/com/bensherriff/siren/audio/AudioHandler.java +++ b/src/main/java/com/bensherriff/siren/audio/AudioHandler.java @@ -38,17 +38,25 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler } public void addTrack(AudioTrack track) { - if (player.getPlayingTrack() == null) { - player.playTrack(track); - } else { - queue.add(track); + if (!player.startTrack(track, true)) { + if (!queue.offer(track)) { + LOGGER.error("Failed to queue track {}", track.getInfo().title); + } } } + public void nextTrack() { + player.startTrack(queue.poll(), false); + } + public void setPaused(boolean paused) { player.setPaused(paused); } + public boolean isPaused() { + return player.isPaused(); + } + public void stopTrack() { player.stopTrack(); } @@ -69,16 +77,19 @@ public class AudioHandler extends AudioEventAdapter implements AudioSendHandler @Override public void onTrackStart(AudioPlayer player, AudioTrack track) { + manager.getListener().getJDA().getPresence().setActivity(Activity.listening(track.getInfo().title)); super.onTrackStart(player, track); } @Override public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { -// LOGGER.debug("Track ended: " + endReason.name() + "; starting next: " + endReason.mayStartNext); - if (queue.isEmpty()) { - manager.getListener().closeAudioConnection(guildID); + LOGGER.debug("Track ended due to {}; {} ", endReason.name(), endReason.mayStartNext ? "starting next track" : "closing connection"); + if (endReason.mayStartNext) { + nextTrack(); } else { - player.playTrack(queue.poll()); + queue.clear(); + manager.getListener().closeAudioConnection(guildID); + manager.getListener().getJDA().getPresence().setActivity(Activity.playing("nothing")); } } diff --git a/src/main/java/com/bensherriff/siren/listener/Listener.java b/src/main/java/com/bensherriff/siren/audio/Listener.java similarity index 60% rename from src/main/java/com/bensherriff/siren/listener/Listener.java rename to src/main/java/com/bensherriff/siren/audio/Listener.java index 77cf67a..872566a 100644 --- a/src/main/java/com/bensherriff/siren/listener/Listener.java +++ b/src/main/java/com/bensherriff/siren/audio/Listener.java @@ -1,17 +1,15 @@ -package com.bensherriff.siren.listener; +package com.bensherriff.siren.audio; -import com.bensherriff.siren.audio.AudioHandler; -import com.bensherriff.siren.audio.PlayerManager; -import com.bensherriff.siren.commands.Command; +import com.bensherriff.siren.commands.*; import com.bensherriff.siren.exceptions.EmptyVoiceChannelException; import com.bensherriff.siren.settings.GuildSettings; import com.bensherriff.siren.settings.Settings; import com.bensherriff.siren.settings.SettingsManager; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.session.ReadyEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.managers.AudioManager; @@ -20,17 +18,19 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; -public abstract class Listener extends ListenerAdapter { - protected static final Logger LOGGER = LogManager.getLogger(Listener.class); +public class Listener extends ListenerAdapter { + private static final Logger LOGGER = LogManager.getLogger(Listener.class); - protected final PlayerManager playerManager; - protected final Map musicManagers; - protected final Settings settings; - protected JDA jda; - - Map commands = new HashMap<>(); + private final PlayerManager playerManager; + private final Map musicManagers; + private final Settings settings; + private final Map commands = new HashMap<>(); + private JDA jda; public Listener(Settings settings) { this.musicManagers = new HashMap<>(); @@ -38,6 +38,29 @@ public abstract class Listener extends ListenerAdapter { this.playerManager = new PlayerManager(this); this.playerManager.initialize(); + + commands.put("play", new PlayCommand(this)); + commands.put("stop", new StopCommand(this)); + commands.put("skip", new SkipCommand(this)); + commands.put("volume", new VolumeCommand(this)); + commands.put("pause", new PauseCommand(this)); + commands.put("resume", new ResumeCommand(this)); + } + + public PlayerManager getPlayerManager() { + return playerManager; + } + + public Map getMusicManagers() { + return musicManagers; + } + + public Settings getSettings() { + return settings; + } + + public Map getCommands() { + return commands; } public JDA getJDA() { @@ -48,14 +71,6 @@ public abstract class Listener extends ListenerAdapter { this.jda = jda; } - public Settings getSettings() { - return settings; - } - - public PlayerManager getPlayerManager() { - return playerManager; - } - public void closeAudioConnection(long guildID) { Guild guild = jda.getGuildById(guildID); if (guild != null) { @@ -63,6 +78,21 @@ public abstract class Listener extends ListenerAdapter { } } + public void connectToVoiceChannel(String userID, AudioManager audioManager) throws EmptyVoiceChannelException { + if (!audioManager.isConnected()) { + Member member = audioManager.getGuild().getMemberById(userID); + if (member != null) { + if (member.getVoiceState() != null && member.getVoiceState().inAudioChannel()) { + VoiceChannel voiceChannel = Objects.requireNonNull(member.getVoiceState().getChannel()).asVoiceChannel(); + LOGGER.debug("Connecting to channel {} in guild {}", voiceChannel.getId(), voiceChannel.getGuild().getId()); + audioManager.openAudioConnection(voiceChannel); + } else { + throw new EmptyVoiceChannelException("Member {} is not connected to a voice channel"); + } + } + } + } + public synchronized AudioHandler getGuildAudioPlayer(Guild guild) throws IOException { long guildId = Long.parseLong(guild.getId()); AudioHandler audioHandler = musicManagers.get(guildId); @@ -87,53 +117,29 @@ public abstract class Listener extends ListenerAdapter { @Override public void onReady(@NotNull ReadyEvent event) { super.onReady(event); + jda.getGuilds().forEach(guild -> { + LOGGER.debug("Updating commands for {}", guild.getId()); + guild.updateCommands().addCommands(commands.values().stream().map(Command::getSlashCommandData).collect(Collectors.toList())).queue(); + }); + super.onReady(event); + LOGGER.info("Ready!"); } - public void playTrack(Guild guild, String userID, AudioHandler audioHandler, AudioTrack track) throws EmptyVoiceChannelException { - connectToVoiceChannel(userID, guild.getAudioManager()); - audioHandler.addTrack(track); - } + @Override + public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + String command = event.getName(); + event.deferReply().queue(); - public void stopTrack(Guild guild) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - audioHandler.stopTrack(); - guild.getAudioManager().closeAudioConnection(); - } - - public void skipTrack(Guild guild) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - audioHandler.stopTrack(); - } - - public void pauseTrack(Guild guild) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - audioHandler.setPaused(true); - } - - public void resumeTrack(Guild guild) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - audioHandler.setPaused(false); - } - - public void changeVolume(Guild guild, int volume) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - settings.getGuildSettings().get(guild.getIdLong()).setVolume(volume); - SettingsManager.write(getSettings()); - audioHandler.setVolume(volume); - } - - public void connectToVoiceChannel(String userID, AudioManager audioManager) throws EmptyVoiceChannelException { - if (!audioManager.isConnected()) { - Member member = audioManager.getGuild().getMemberById(userID); - if (member != null) { - if (member.getVoiceState() != null && member.getVoiceState().inAudioChannel()) { - VoiceChannel voiceChannel = Objects.requireNonNull(member.getVoiceState().getChannel()).asVoiceChannel(); - LOGGER.debug("Connecting to channel {} in guild {}", voiceChannel.getId(), voiceChannel.getGuild().getId()); - audioManager.openAudioConnection(voiceChannel); - } else { - throw new EmptyVoiceChannelException("Member {} is not connected to a voice channel"); - } + try { + if (commands.containsKey(command)) { + commands.get(command).doCommand(event); + } else { + event.getHook().sendMessage("Unexpected command received.").queue(); } + } catch (Exception ex) { + LOGGER.error(ex.getMessage()); + event.getHook().sendMessage("An error occurred while processing your command. Please contact your administrator.").queue(); } + super.onSlashCommandInteraction(event); } } diff --git a/src/main/java/com/bensherriff/siren/audio/PlayerManager.java b/src/main/java/com/bensherriff/siren/audio/PlayerManager.java index c4b26d8..7561d7f 100644 --- a/src/main/java/com/bensherriff/siren/audio/PlayerManager.java +++ b/src/main/java/com/bensherriff/siren/audio/PlayerManager.java @@ -1,6 +1,5 @@ package com.bensherriff.siren.audio; -import com.bensherriff.siren.listener.Listener; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; diff --git a/src/main/java/com/bensherriff/siren/commands/Command.java b/src/main/java/com/bensherriff/siren/commands/Command.java index 18b0078..dff016d 100644 --- a/src/main/java/com/bensherriff/siren/commands/Command.java +++ b/src/main/java/com/bensherriff/siren/commands/Command.java @@ -1,18 +1,40 @@ package com.bensherriff.siren.commands; -import com.bensherriff.siren.listener.Listener; +import com.bensherriff.siren.audio.Listener; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; public abstract class Command { + protected static final Logger LOGGER = LogManager.getLogger(Command.class); + + protected final Listener listener; - protected String name; + protected SlashCommandData slashCommandData; + + protected boolean required = false; public Command(Listener listener) { this.listener = listener; } - public abstract void doCommand(CommandEvent event); + public abstract void doCommand(SlashCommandInteractionEvent event) throws IOException; - public String getName() { - return name; + public SlashCommandData getSlashCommandData() { + return slashCommandData; + } + + protected Guild getGuild(SlashCommandInteractionEvent event) throws IOException { + Guild guild = event.getGuild(); + if (guild == null) { + throw new IOException("Could not find the current guild."); + } + else { + return guild; + } } } diff --git a/src/main/java/com/bensherriff/siren/commands/CommandEvent.java b/src/main/java/com/bensherriff/siren/commands/CommandEvent.java deleted file mode 100644 index edbbf1b..0000000 --- a/src/main/java/com/bensherriff/siren/commands/CommandEvent.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.bensherriff.siren.commands; - -import com.bensherriff.siren.audio.AudioHandler; -import com.bensherriff.siren.exceptions.InvalidCommandException; -import com.bensherriff.siren.listener.Listener; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; - -import java.util.ArrayList; -import java.util.List; - -public class CommandEvent { - - private final Command command; - private final String userId; - private final Guild guild; - private final List args = new ArrayList<>(); - private final AudioHandler audioHandler; - private final TextChannel textChannel; - - private CommandEvent(CommandBuilder builder) { - this.command = builder.command; - this.userId = builder.userId; - this.guild = builder.guild; - this.args.addAll(builder.args); - this.audioHandler = builder.audioHandler; - this.textChannel = builder.textChannel; - } - - public Command getCommand() { - return command; - } - - public String getUserId() { - return userId; - } - - public Guild getGuild() { - return guild; - } - - public List getArgs() { - return args; - } - - public AudioHandler getAudioHandler() { - return audioHandler; - } - - public TextChannel getTextChannel() { - return textChannel; - } - - public static class CommandBuilder { - private final Listener listener; - private final String commandText; - private final String userId; - private Command command; - private Guild guild; - private List args = new ArrayList<>(); - private AudioHandler audioHandler; - private TextChannel textChannel; - - public CommandBuilder(Listener listener, String commandText, String userId) { - this.listener = listener; - this.commandText = commandText; - this.userId = userId; - } - - public CommandBuilder setGuild(Guild guild) { - this.guild = guild; - return this; - } - - public CommandBuilder setArgs(List args) { - this.args = args; - return this; - } - - public CommandBuilder setAudioHandler(AudioHandler audioHandler) { - this.audioHandler = audioHandler; - return this; - } - - public CommandBuilder setTextChannel(TextChannel textChannel) { - this.textChannel = textChannel; - return this; - } - - public CommandEvent build() throws InvalidCommandException { - if ("play".equals(this.commandText)) { - this.command = new PlayCommand(this.listener); - } else { - throw new InvalidCommandException(this.commandText + " is not a valid command"); - } - return new CommandEvent(this); - } - } -} diff --git a/src/main/java/com/bensherriff/siren/commands/PauseCommand.java b/src/main/java/com/bensherriff/siren/commands/PauseCommand.java new file mode 100644 index 0000000..c257303 --- /dev/null +++ b/src/main/java/com/bensherriff/siren/commands/PauseCommand.java @@ -0,0 +1,29 @@ +package com.bensherriff.siren.commands; + +import com.bensherriff.siren.audio.AudioHandler; +import com.bensherriff.siren.audio.Listener; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import java.io.IOException; + +public class PauseCommand extends Command { + + public PauseCommand(Listener listener) { + super(listener); + slashCommandData = Commands.slash("pause", "Pause the current track"); + } + + @Override + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + Guild guild = getGuild(event); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); + if (audioHandler.isPaused()) { + event.getHook().sendMessage("Playback is already paused.").queue(); + } else { + audioHandler.setPaused(false); + event.getHook().sendMessage("Pausing track...").queue(); + } + } +} diff --git a/src/main/java/com/bensherriff/siren/commands/PlayCommand.java b/src/main/java/com/bensherriff/siren/commands/PlayCommand.java index 2168011..ac73366 100644 --- a/src/main/java/com/bensherriff/siren/commands/PlayCommand.java +++ b/src/main/java/com/bensherriff/siren/commands/PlayCommand.java @@ -2,38 +2,42 @@ package com.bensherriff.siren.commands; import com.bensherriff.siren.audio.AudioHandler; import com.bensherriff.siren.exceptions.EmptyVoiceChannelException; -import com.bensherriff.siren.listener.Listener; +import com.bensherriff.siren.audio.Listener; 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 net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.Commands; import java.io.IOException; +import java.util.Objects; public class PlayCommand extends Command { public PlayCommand(Listener listener) { super(listener); - this.name = "play"; + slashCommandData = Commands.slash("play", "Play a track from a URL") + .addOption(OptionType.STRING, "url", "Track URL", true); } @Override - public void doCommand(CommandEvent event) { + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + String userID = event.getUser().getId(); + Guild guild = getGuild(event); + String trackURL = Objects.requireNonNull(event.getOption("url")).getAsString(); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); - } - - private void loadAndPlay(final TextChannel channel, final String userID, final String trackUrl) throws IOException { - AudioHandler audioHandler = this.listener.getGuildAudioPlayer(channel.getGuild()); - Listener listener = this.listener; - listener.getPlayerManager().loadItemOrdered(audioHandler, trackUrl, new AudioLoadResultHandler() { + listener.getPlayerManager().loadItemOrdered(audioHandler, trackURL, new AudioLoadResultHandler() { @Override public void trackLoaded(AudioTrack track) { try { - listener.playTrack(channel.getGuild(), userID, audioHandler, track); - channel.sendMessage("Adding **" + track.getInfo().title + "** to queue").queue(); + playTrack(guild, userID, audioHandler, track); + event.getHook().sendMessage("Adding **" + track.getInfo().title + "** to queue...").queue(); } catch (EmptyVoiceChannelException e) { - channel.sendMessage("You must connect to a voice channel first!").queue(); + event.getHook().sendMessage("You must be connected to a voice channel in order to play tracks!").queue(); } } @@ -46,22 +50,33 @@ public class PlayCommand extends Command { } try { - listener.playTrack(channel.getGuild(), userID, audioHandler, firstTrack); - channel.sendMessage("Adding **" + firstTrack.getInfo().title + "** to queue (first track of playlist " + playlist.getName() + ")").queue(); + playTrack(guild, userID, audioHandler, firstTrack); + event.getHook().sendMessage("Adding **" + firstTrack.getInfo().title + "** to queue (first track of playlist " + playlist.getName() + ")...").queue(); } catch (EmptyVoiceChannelException e) { - channel.sendMessage("You must connect to a voice channel first!").queue(); + event.getHook().sendMessage("You must be connected to a voice channel in order to play tracks!").queue(); } } @Override public void noMatches() { - channel.sendMessage("Nothing found by " + trackUrl).queue(); + event.getHook().sendMessage("Nothing found by " + trackURL).queue(); } @Override public void loadFailed(FriendlyException exception) { - channel.sendMessage("Could not play: " + exception.getMessage()).queue(); + String msg = "Failed to play track"; + if (exception.getMessage().contains("Unknown file format")) { + event.getHook().sendMessage(msg + ". " + exception.getMessage()).queue(); + } else { + event.getHook().sendMessage(msg + ". Please contact your administrator.").queue(); + } + LOGGER.error("{}: {}", msg, exception.getMessage()); } }); } + + public void playTrack(Guild guild, String userID, AudioHandler audioHandler, AudioTrack track) throws EmptyVoiceChannelException { + listener.connectToVoiceChannel(userID, guild.getAudioManager()); + audioHandler.addTrack(track); + } } diff --git a/src/main/java/com/bensherriff/siren/commands/ResumeCommand.java b/src/main/java/com/bensherriff/siren/commands/ResumeCommand.java new file mode 100644 index 0000000..ac4f871 --- /dev/null +++ b/src/main/java/com/bensherriff/siren/commands/ResumeCommand.java @@ -0,0 +1,29 @@ +package com.bensherriff.siren.commands; + +import com.bensherriff.siren.audio.AudioHandler; +import com.bensherriff.siren.audio.Listener; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import java.io.IOException; + +public class ResumeCommand extends Command { + + public ResumeCommand(Listener listener) { + super(listener); + slashCommandData = Commands.slash("resume", "Resume the current track"); + } + + @Override + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + Guild guild = getGuild(event); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); + if (audioHandler.isPaused()) { + audioHandler.setPaused(false); + event.getHook().sendMessage("Resuming track...").queue(); + } else { + event.getHook().sendMessage("Playback is not currently paused.").queue(); + } + } +} diff --git a/src/main/java/com/bensherriff/siren/commands/SkipCommand.java b/src/main/java/com/bensherriff/siren/commands/SkipCommand.java new file mode 100644 index 0000000..cee7044 --- /dev/null +++ b/src/main/java/com/bensherriff/siren/commands/SkipCommand.java @@ -0,0 +1,25 @@ +package com.bensherriff.siren.commands; + +import com.bensherriff.siren.audio.AudioHandler; +import com.bensherriff.siren.audio.Listener; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import java.io.IOException; + +public class SkipCommand extends Command { + + public SkipCommand(Listener listener) { + super(listener); + slashCommandData = Commands.slash("skip", "Skip the current track"); + } + + @Override + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + Guild guild = getGuild(event); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); + audioHandler.nextTrack(); + event.getHook().sendMessage("Skipping track...").queue(); + } +} diff --git a/src/main/java/com/bensherriff/siren/commands/StopCommand.java b/src/main/java/com/bensherriff/siren/commands/StopCommand.java new file mode 100644 index 0000000..38dfbb5 --- /dev/null +++ b/src/main/java/com/bensherriff/siren/commands/StopCommand.java @@ -0,0 +1,26 @@ +package com.bensherriff.siren.commands; + +import com.bensherriff.siren.audio.AudioHandler; +import com.bensherriff.siren.audio.Listener; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import java.io.IOException; + +public class StopCommand extends Command { + + public StopCommand(Listener listener) { + super(listener); + slashCommandData = Commands.slash("stop", "Stop playing tracks and clear the queue"); + } + + @Override + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + Guild guild = getGuild(event); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); + audioHandler.stopTrack(); + guild.getAudioManager().closeAudioConnection(); + event.getHook().sendMessage("Stopping the current track and clearing the queue...").queue(); + } +} diff --git a/src/main/java/com/bensherriff/siren/commands/VolumeCommand.java b/src/main/java/com/bensherriff/siren/commands/VolumeCommand.java new file mode 100644 index 0000000..8dbe3b7 --- /dev/null +++ b/src/main/java/com/bensherriff/siren/commands/VolumeCommand.java @@ -0,0 +1,32 @@ +package com.bensherriff.siren.commands; + +import com.bensherriff.siren.audio.AudioHandler; +import com.bensherriff.siren.audio.Listener; +import com.bensherriff.siren.settings.SettingsManager; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.Commands; + +import java.io.IOException; +import java.util.Objects; + +public class VolumeCommand extends Command { + + public VolumeCommand(Listener listener) { + super(listener); + slashCommandData = Commands.slash("volume", "Set the volume") + .addOption(OptionType.INTEGER, "volume", "Updated value", true); + } + + @Override + public void doCommand(SlashCommandInteractionEvent event) throws IOException { + Guild guild = getGuild(event); + int volume = Objects.requireNonNull(event.getOption("volume")).getAsInt(); + listener.getSettings().getGuildSettings().get(guild.getIdLong()).setVolume(volume); + SettingsManager.write(listener.getSettings()); + AudioHandler audioHandler = listener.getGuildAudioPlayer(guild); + audioHandler.setVolume(volume); + event.getHook().sendMessage("Setting volume to " + volume + "...").queue(); + } +} diff --git a/src/main/java/com/bensherriff/siren/listener/SlashListener.java b/src/main/java/com/bensherriff/siren/listener/SlashListener.java deleted file mode 100644 index c5ccfb9..0000000 --- a/src/main/java/com/bensherriff/siren/listener/SlashListener.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.bensherriff.siren.listener; - -import com.bensherriff.siren.audio.AudioHandler; -import com.bensherriff.siren.exceptions.EmptyVoiceChannelException; -import com.bensherriff.siren.settings.Settings; -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 net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.events.session.ReadyEvent; -import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.commands.build.Commands; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.Objects; - -public class SlashListener extends Listener { - - public SlashListener(Settings settings) { - super(settings); - } - - @Override - public void onReady(@NotNull ReadyEvent event) { - jda.getGuilds().forEach(guild -> { - guild.updateCommands().addCommands( - Commands.slash("play", "Play a track from a URL") - .addOption(OptionType.STRING, "url", "Track URL", true), - Commands.slash("skip", "Skip the current track"), - Commands.slash("stop", "Stop playing tracks and clear the queue"), - Commands.slash("volume", "Set the volume") - .addOption(OptionType.INTEGER, "volume", "Updated Volume", true), - Commands.slash("pause", "Pause the current track"), - Commands.slash("resume", "Resume the current paused track") - ).queue(); - }); - super.onReady(event); - } - - @Override - public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { - - String userId = event.getUser().getId(); - Guild guild = event.getGuild(); - String command = event.getName(); - event.deferReply().queue(); - - try { - switch (command) { - case "play" -> { - String trackURL = Objects.requireNonNull(event.getOption("url")).getAsString(); - loadAndPlay(guild, userId, trackURL, event); - } - case "skip" -> { - skipTrack(guild); - event.getHook().sendMessage("Skipped to the next track").queue(); - } - case "stop" -> { - stopTrack(guild); - event.getHook().sendMessage("Stopped track and cleared queue").queue(); - } - case "volume" -> { - int volume = Objects.requireNonNull(event.getOption("volume")).getAsInt(); - try { - changeVolume(guild, volume); - } catch (IOException ex) { - event.getHook().sendMessage("Unable to set the volume").queue(); - LOGGER.error(ex.getMessage()); - } - event.getHook().sendMessage("Set volume to " + volume).queue(); - } - case "pause" -> { - pauseTrack(guild); - event.getHook().sendMessage("Pausing track").queue(); - } - case "resume" -> { - resumeTrack(guild); - event.getHook().sendMessage("Resumed track").queue(); - } - default -> event.getHook().sendMessage("Invalid command").queue(); - } - } catch (IOException ex) { - LOGGER.error(ex.getMessage()); - } - super.onSlashCommandInteraction(event); - } - - private void loadAndPlay(Guild guild, final String userID, final String trackUrl, SlashCommandInteractionEvent event) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(guild); - - playerManager.loadItemOrdered(audioHandler, trackUrl, new AudioLoadResultHandler() { - @Override - public void trackLoaded(AudioTrack track) { - try { - playTrack(guild, userID, audioHandler, track); - event.getHook().sendMessage("Adding **" + track.getInfo().title + "** to queue").queue(); - } catch (EmptyVoiceChannelException e) { - event.getHook().sendMessage("You must connect to a voice channel first!").queue(); - } - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - AudioTrack firstTrack = playlist.getSelectedTrack(); - - if (firstTrack == null) { - firstTrack = playlist.getTracks().get(0); - } - - try { - playTrack(guild, userID, audioHandler, firstTrack); - event.getHook().sendMessage("Adding **" + firstTrack.getInfo().title + "** to queue (first track of playlist " + playlist.getName() + ")").queue(); - } catch (EmptyVoiceChannelException e) { - event.getHook().sendMessage("You must connect to a voice channel first!").queue(); - } - } - - @Override - public void noMatches() { - event.getHook().sendMessage("Nothing found by " + trackUrl).queue(); - } - - @Override - public void loadFailed(FriendlyException exception) { - event.getHook().sendMessage("Could not play: " + exception.getMessage()).queue(); - } - }); - } -} diff --git a/src/main/java/com/bensherriff/siren/listener/TextListener.java b/src/main/java/com/bensherriff/siren/listener/TextListener.java deleted file mode 100644 index 32f673f..0000000 --- a/src/main/java/com/bensherriff/siren/listener/TextListener.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.bensherriff.siren.listener; - -import com.bensherriff.siren.audio.AudioHandler; -import com.bensherriff.siren.commands.CommandEvent; -import com.bensherriff.siren.exceptions.EmptyVoiceChannelException; -import com.bensherriff.siren.exceptions.InvalidCommandException; -import com.bensherriff.siren.settings.Settings; -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 net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.Arrays; - -public class TextListener extends Listener { - - public TextListener(Settings settings) { - super(settings); - } - - @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { - if (event.getAuthor().isBot()) return; - -// Command command = parseCommand(event.getMessage().getContentRaw().split(" ")); - String[] command = event.getMessage().getContentRaw().split(" "); - TextChannel channel = event.getChannel().asTextChannel(); - String userID = event.getAuthor().getId(); - Guild guild = channel.getGuild(); - - try { - if ("!play".equals(command[0]) && command.length == 2) { - loadAndPlay(channel, userID, command[1]); - } else if ("!skip".equals(command[0])) { - skipTrack(guild); - channel.sendMessage("Skipped to the next track").queue(); - } else if ("!stop".equals(command[0])) { - stopTrack(guild); - channel.sendMessage("Stopped track and cleared queue").queue(); - } else if ("!volume".equals(command[0]) && command.length == 2) { - int volume = Integer.parseInt(command[1]); - try { - changeVolume(guild, volume); - } catch (IOException ex) { - channel.sendMessage("Unable to update the settings file.").queue(); - LOGGER.error(ex.getMessage()); - } - channel.sendMessage("Set volume to " + command[1]).queue(); - } else if ("!pause".equals(command[0])) { - pauseTrack(guild); - channel.sendMessage("Paused track").queue(); - } else if ("!resume".equals(command[0])) { - resumeTrack(guild); - channel.sendMessage("Resumed track").queue(); - } - } catch (IOException ex) { - LOGGER.error(ex.getMessage()); - } - - super.onMessageReceived(event); - } - - private CommandEvent parseCommand(MessageReceivedEvent event) throws IOException, InvalidCommandException { - String[] input = event.getMessage().getContentRaw().split(" "); - TextChannel channel = event.getChannel().asTextChannel(); - String userID = event.getAuthor().getId(); - Guild guild = channel.getGuild(); - AudioHandler audioHandler = getGuildAudioPlayer(guild); - - return new CommandEvent.CommandBuilder(this, input[0], userID) - .setTextChannel(channel) - .setGuild(guild) - .setAudioHandler(audioHandler) - .setArgs(Arrays.asList(input).subList(1, input.length)) - .build(); - } - - private void loadAndPlay(final TextChannel channel, final String userID, final String trackUrl) throws IOException { - AudioHandler audioHandler = getGuildAudioPlayer(channel.getGuild()); - - playerManager.loadItemOrdered(audioHandler, trackUrl, new AudioLoadResultHandler() { - @Override - public void trackLoaded(AudioTrack track) { - try { - playTrack(channel.getGuild(), userID, audioHandler, track); - channel.sendMessage("Adding **" + track.getInfo().title + "** to queue").queue(); - } catch (EmptyVoiceChannelException e) { - channel.sendMessage("You must connect to a voice channel first!").queue(); - } - } - - @Override - public void playlistLoaded(AudioPlaylist playlist) { - AudioTrack firstTrack = playlist.getSelectedTrack(); - - if (firstTrack == null) { - firstTrack = playlist.getTracks().get(0); - } - - try { - playTrack(channel.getGuild(), userID, audioHandler, firstTrack); - channel.sendMessage("Adding **" + firstTrack.getInfo().title + "** to queue (first track of playlist " + playlist.getName() + ")").queue(); - } catch (EmptyVoiceChannelException e) { - channel.sendMessage("You must connect to a voice channel first!").queue(); - } - } - - @Override - public void noMatches() { - channel.sendMessage("Nothing found by " + trackUrl).queue(); - } - - @Override - public void loadFailed(FriendlyException exception) { - channel.sendMessage("Could not play: " + exception.getMessage()).queue(); - } - }); - } -} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index 447b8eb..32c93a1 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -1,13 +1,33 @@ + + logs + siren + %d{HH:mm:ss.SSS} | %-5level | %msg%n + - - + + + + + + + + + + + + - - + + + + + + \ No newline at end of file