diff --git a/src/main/java/dev/logal/logalbot/audio/RequestedTrack.java b/src/main/java/dev/logal/logalbot/audio/RequestedTrack.java new file mode 100644 index 0000000..899efd6 --- /dev/null +++ b/src/main/java/dev/logal/logalbot/audio/RequestedTrack.java @@ -0,0 +1,41 @@ +package dev.logal.logalbot.audio; + +// Copyright 2019 Logan Fick + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// https://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; + +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.utils.Checks; + +public final class RequestedTrack { + private final AudioTrack track; + private final Member requester; + + public RequestedTrack(final AudioTrack track, final Member requester) { + Checks.notNull(track, "Track"); + Checks.notNull(requester, "Requester"); + + this.track = track; + this.requester = requester; + } + + public final AudioTrack getTrack() { + return this.track; + } + + public final Member getRequester() { + return this.requester; + } +} \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java b/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java index cdbc925..629feae 100644 --- a/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java +++ b/src/main/java/dev/logal/logalbot/audio/TrackLoadHandler.java @@ -14,7 +14,7 @@ package dev.logal.logalbot.audio; // See the License for the specific language governing permissions and // limitations under the License. -import java.util.ArrayList; +import java.util.LinkedList; import java.util.concurrent.TimeUnit; import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; @@ -82,10 +82,11 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { return; } - scheduler.addToQueue(track, requester); + final RequestedTrack requestedTrack = new RequestedTrack(track, requester); + scheduler.addToQueue(requestedTrack); response = new CommandResponse("notes", this.requester.getAsMention() + " added the following track to the queue:"); - response.attachEmbed(TrackUtil.trackInfoEmbed(track)); + response.attachEmbed(TrackUtil.trackInfoEmbed(requestedTrack)); response.sendResponse(this.channel); } @@ -97,11 +98,13 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { final TrackScheduler scheduler = AudioUtil.getTrackScheduler(this.channel.getGuild()); final AudioTrack selectedTrack = playlist.getSelectedTrack(); - AudioTrack track = null; + final AudioTrack track; if (!playlist.isSearchResult() && selectedTrack != null) { track = selectedTrack; } else if (playlist.isSearchResult()) { track = playlist.getTracks().get(0); + } else { + track = null; } if (track != null) { @@ -123,10 +126,11 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { } if ((info.length >= 60000 && info.length <= 900000) || PermissionManager.isWhitelisted(this.requester)) { - scheduler.addToQueue(track, this.requester); + final RequestedTrack requestedTrack = new RequestedTrack(track, requester); + scheduler.addToQueue(requestedTrack); response = new CommandResponse("notes", this.requester.getAsMention() + " added the following track to the queue:"); - response.attachEmbed(TrackUtil.trackInfoEmbed(track)); + response.attachEmbed(TrackUtil.trackInfoEmbed(requestedTrack)); response.sendResponse(this.channel); } else { response = new CommandResponse("no_entry_sign", "Sorry " + this.requester.getAsMention() @@ -136,12 +140,13 @@ public final class TrackLoadHandler implements AudioLoadResultHandler { } } else { if (PermissionManager.isWhitelisted(this.requester)) { - final ArrayList addedTracks = new ArrayList<>(); + final LinkedList addedTracks = new LinkedList<>(); for (final AudioTrack playlistTrack : playlist.getTracks()) { if (!scheduler.isQueueFull()) { if (!scheduler.isQueued(playlistTrack) && !playlistTrack.getInfo().isStream) { - scheduler.addToQueue(playlistTrack, this.requester); - addedTracks.add(playlistTrack); + final RequestedTrack requestedTrack = new RequestedTrack(track, requester); + scheduler.addToQueue(requestedTrack); + addedTracks.add(requestedTrack); } } else { break; diff --git a/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java b/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java index e982814..7b86bf3 100644 --- a/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java +++ b/src/main/java/dev/logal/logalbot/audio/TrackScheduler.java @@ -14,8 +14,8 @@ package dev.logal.logalbot.audio; // See the License for the specific language governing permissions and // limitations under the License. -import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -44,7 +44,7 @@ public final class TrackScheduler extends AudioEventAdapter { private static final Logger logger = LoggerFactory.getLogger(TrackScheduler.class); private final Guild guild; - private final ArrayList queue = new ArrayList<>(250); + private final LinkedList queue = new LinkedList<>(); private boolean queueLocked = false; private ScheduledFuture idleLogoutTask; @@ -54,10 +54,10 @@ public final class TrackScheduler extends AudioEventAdapter { this.guild = guild; } - public final void addToQueue(final AudioTrack track, final Member requester) { - Checks.notNull(track, "Track"); - Checks.notNull(requester, "Requester"); + public final void addToQueue(final RequestedTrack requestedTrack) { + Checks.notNull(requestedTrack, "Requested Track"); + final Member requester = requestedTrack.getRequester(); if (this.queueLocked && !PermissionManager.isWhitelisted(requester)) { return; } @@ -67,27 +67,30 @@ public final class TrackScheduler extends AudioEventAdapter { } final User user = requester.getUser(); + final AudioTrack track = requestedTrack.getTrack(); logger.info(user.getName() + " (" + user.getId() + ") added '" + track.getInfo().title + "' to the queue in " + this.guild.getName() + " (" + this.guild.getId() + ")."); - this.queue.add(track); + if (!AudioUtil.isTrackLoaded(this.guild)) { AudioUtil.openAudioConnection(VoiceChannelUtil.getVoiceChannelMemberIsConnectedTo(requester)); - AudioUtil.playTrack(this.guild, this.queue.remove(0)); + AudioUtil.playTrack(this.guild, requestedTrack); + } else { + this.queue.add(requestedTrack); } } public final void removeFromQueue(final int index) { Checks.notNull(index, "Index"); - logger.info("Track '" + queue.remove(index).getInfo().title + "' has been removed from the queue in " + logger.info("Track '" + queue.remove(index).getTrack().getInfo().title + "' has been removed from the queue in " + this.guild.getName() + " (" + this.guild.getId() + ")."); } public final boolean isQueued(final AudioTrack track) { Checks.notNull(track, "Track"); - for (final AudioTrack queuedTrack : queue) { - if (track.getInfo().identifier.equals(queuedTrack.getInfo().identifier)) { + for (final RequestedTrack queuedTrack : queue) { + if (track.getInfo().identifier.equals(queuedTrack.getTrack().getInfo().identifier)) { return true; } } @@ -120,13 +123,13 @@ public final class TrackScheduler extends AudioEventAdapter { Collections.shuffle(this.queue); } - public final ArrayList getQueue() { + public final LinkedList getQueue() { return this.queue; } public final void skipCurrentTrack() { if (AudioUtil.isTrackLoaded(this.guild)) { - logger.info("Track '" + AudioUtil.getLoadedTrack(this.guild).getInfo().title + "' in " + logger.info("Track '" + AudioUtil.getLoadedTrack(this.guild).getTrack().getInfo().title + "' in " + this.guild.getName() + " (" + this.guild.getId() + ") been skipped."); AudioUtil.stopTrack(this.guild); } diff --git a/src/main/java/dev/logal/logalbot/commands/audio/ForceSkip.java b/src/main/java/dev/logal/logalbot/commands/audio/ForceSkip.java index 86d552c..c78e70a 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/ForceSkip.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/ForceSkip.java @@ -16,8 +16,7 @@ package dev.logal.logalbot.commands.audio; import java.util.concurrent.TimeUnit; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; - +import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; import dev.logal.logalbot.utils.AudioUtil; @@ -45,7 +44,7 @@ public final class ForceSkip implements Command { + "` in order to force skip tracks.").setDeletionDelay(10, TimeUnit.SECONDS); } - final AudioTrack skippedTrack = AudioUtil.getLoadedTrack(guild); + final RequestedTrack skippedTrack = AudioUtil.getLoadedTrack(guild); AudioUtil.getTrackScheduler(guild).skipCurrentTrack(); final CommandResponse response = new CommandResponse("gun", diff --git a/src/main/java/dev/logal/logalbot/commands/audio/Queue.java b/src/main/java/dev/logal/logalbot/commands/audio/Queue.java index 430e3fc..63f5332 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/Queue.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/Queue.java @@ -17,8 +17,7 @@ package dev.logal.logalbot.commands.audio; import java.util.List; import java.util.concurrent.TimeUnit; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; - +import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; import dev.logal.logalbot.utils.AudioUtil; @@ -53,7 +52,7 @@ public final class Queue implements Command { } } - final List queue = AudioUtil.getTrackScheduler(guild).getQueue(); + final List queue = AudioUtil.getTrackScheduler(guild).getQueue(); if (page != 1) { response.addReactionCallback("arrow_left", (reactor, message) -> { ReactionCallbackManager.unregisterMessage(message, true); @@ -69,7 +68,7 @@ public final class Queue implements Command { } response.setReactionCallbackTarget(executor); - response.setReactionCallbackExpireDelay(3, TimeUnit.SECONDS); + response.setReactionCallbackExpireDelay(15, TimeUnit.SECONDS); response.attachEmbed(TrackUtil.pagedTrackListInfoEmbed(queue, page)); return response; } diff --git a/src/main/java/dev/logal/logalbot/commands/audio/Remove.java b/src/main/java/dev/logal/logalbot/commands/audio/Remove.java index cea09ab..d26aa6a 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/Remove.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/Remove.java @@ -16,8 +16,7 @@ package dev.logal.logalbot.commands.audio; import java.util.concurrent.TimeUnit; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; - +import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.audio.TrackScheduler; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; @@ -89,7 +88,7 @@ public final class Remove implements Command { } try { - final AudioTrack removedTrack = scheduler.getQueue().get(index - 1); + final RequestedTrack removedTrack = scheduler.getQueue().get(index - 1); scheduler.removeFromQueue(index - 1); final CommandResponse response = new CommandResponse("scissors", diff --git a/src/main/java/dev/logal/logalbot/commands/audio/Skip.java b/src/main/java/dev/logal/logalbot/commands/audio/Skip.java index 3e6c22c..5c1b7b6 100644 --- a/src/main/java/dev/logal/logalbot/commands/audio/Skip.java +++ b/src/main/java/dev/logal/logalbot/commands/audio/Skip.java @@ -16,8 +16,7 @@ package dev.logal.logalbot.commands.audio; import java.util.concurrent.TimeUnit; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; - +import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.commands.Command; import dev.logal.logalbot.commands.CommandResponse; import dev.logal.logalbot.utils.AudioUtil; @@ -54,7 +53,7 @@ public final class Skip implements Command { SkipTracker.registerVote(executor); if (SkipTracker.shouldSkip(guild)) { - final AudioTrack skippedTrack = AudioUtil.getLoadedTrack(guild); + final RequestedTrack skippedTrack = AudioUtil.getLoadedTrack(guild); AudioUtil.getTrackScheduler(guild).skipCurrentTrack(); final CommandResponse response = new CommandResponse("gun", executor.getAsMention() + " was the last required vote. The following track has been skipped:"); diff --git a/src/main/java/dev/logal/logalbot/utils/AudioUtil.java b/src/main/java/dev/logal/logalbot/utils/AudioUtil.java index 3b592cb..b6e400d 100644 --- a/src/main/java/dev/logal/logalbot/utils/AudioUtil.java +++ b/src/main/java/dev/logal/logalbot/utils/AudioUtil.java @@ -20,12 +20,12 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; -import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import dev.logal.logalbot.audio.AudioPlayerSendHandler; +import dev.logal.logalbot.audio.RequestedTrack; import dev.logal.logalbot.audio.TrackLoadHandler; import dev.logal.logalbot.audio.TrackScheduler; import net.dv8tion.jda.core.entities.Guild; @@ -39,8 +39,9 @@ public final class AudioUtil { private static final Logger logger = LoggerFactory.getLogger(AudioUtil.class); private static final AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); - private static final HashMap players = new HashMap<>(); - private static final HashMap schedulers = new HashMap<>(); + private static final HashMap players = new HashMap<>(); + private static final HashMap schedulers = new HashMap<>(); + private static final HashMap loadedTracks = new HashMap<>(); private AudioUtil() { // Static access only. @@ -53,9 +54,9 @@ public final class AudioUtil { public static final void initialize(final Guild guild) { Checks.notNull(guild, "Guild"); - players.put(guild.getId(), playerManager.createPlayer()); - schedulers.put(guild.getId(), new TrackScheduler(guild)); - players.get(guild.getId()).addListener(schedulers.get(guild.getId())); + players.put(guild.getIdLong(), playerManager.createPlayer()); + schedulers.put(guild.getIdLong(), new TrackScheduler(guild)); + players.get(guild.getIdLong()).addListener(schedulers.get(guild.getIdLong())); try { setVolume(guild, Integer.parseInt(DataManager.getGuildValue(guild, "defaultVolume"))); @@ -75,7 +76,7 @@ public final class AudioUtil { final Guild guild = channel.getGuild(); final AudioManager audioManager = guild.getAudioManager(); - audioManager.setSendingHandler(new AudioPlayerSendHandler(players.get(guild.getId()))); + audioManager.setSendingHandler(new AudioPlayerSendHandler(players.get(guild.getIdLong()))); audioManager.openAudioConnection(channel); } @@ -97,17 +98,19 @@ public final class AudioUtil { return guild.getAudioManager().isConnected(); } - public static final void playTrack(final Guild guild, final AudioTrack track) { + public static final void playTrack(final Guild guild, final RequestedTrack track) { Checks.notNull(guild, "Guild"); - Checks.notNull(track, "Track"); + Checks.notNull(track, "Requested Track"); - players.get(guild.getId()).playTrack(track); + players.get(guild.getIdLong()).playTrack(track.getTrack()); + loadedTracks.put(guild.getIdLong(), track); } public static final void stopTrack(final Guild guild) { Checks.notNull(guild, "Guild"); - players.get(guild.getId()).stopTrack(); + players.get(guild.getIdLong()).stopTrack(); + loadedTracks.remove(guild.getIdLong()); } public static final boolean isTrackLoaded(final Guild guild) { @@ -116,10 +119,10 @@ public final class AudioUtil { return !(getLoadedTrack(guild) == null); } - public static final AudioTrack getLoadedTrack(final Guild guild) { + public static final RequestedTrack getLoadedTrack(final Guild guild) { Checks.notNull(guild, "Guild"); - return players.get(guild.getId()).getPlayingTrack(); + return loadedTracks.get(guild.getIdLong()); } public static final void setPausedState(final Guild guild, final boolean pausedState) { @@ -127,7 +130,7 @@ public final class AudioUtil { Checks.notNull(pausedState, "Paused state"); guild.getAudioManager().setSelfMuted(pausedState); - players.get(guild.getId()).setPaused(pausedState); + players.get(guild.getIdLong()).setPaused(pausedState); if (pausedState) { logger.info("The audio player was paused in " + guild.getName() + " (" + guild.getId() + ")."); @@ -139,14 +142,14 @@ public final class AudioUtil { public static final boolean isPlayerPaused(final Guild guild) { Checks.notNull(guild, "Guild"); - return players.get(guild.getId()).isPaused(); + return players.get(guild.getIdLong()).isPaused(); } public static final void setVolume(final Guild guild, final int volume) { Checks.notNull(guild, "Guild"); Checks.positive(volume, "Volume"); - players.get(guild.getId()).setVolume(volume); + players.get(guild.getIdLong()).setVolume(volume); logger.info("The audio player's volume was set to " + getVolume(guild) + "% in " + guild.getName() + " (" + guild.getId() + ")."); } @@ -154,7 +157,7 @@ public final class AudioUtil { public static final int getVolume(final Guild guild) { Checks.notNull(guild, "Guild"); - return players.get(guild.getId()).getVolume(); + return players.get(guild.getIdLong()).getVolume(); } public static final void findTrack(final String query, final Member requester, final TextChannel channel) { @@ -168,6 +171,6 @@ public final class AudioUtil { public static final TrackScheduler getTrackScheduler(final Guild guild) { Checks.notNull(guild, "Guild"); - return schedulers.get(guild.getId()); + return schedulers.get(guild.getIdLong()); } } \ No newline at end of file diff --git a/src/main/java/dev/logal/logalbot/utils/TrackUtil.java b/src/main/java/dev/logal/logalbot/utils/TrackUtil.java index 799aa60..aef77ac 100644 --- a/src/main/java/dev/logal/logalbot/utils/TrackUtil.java +++ b/src/main/java/dev/logal/logalbot/utils/TrackUtil.java @@ -19,9 +19,11 @@ import java.util.List; import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; +import dev.logal.logalbot.audio.RequestedTrack; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.User; import net.dv8tion.jda.core.utils.Checks; public final class TrackUtil { @@ -29,13 +31,18 @@ public final class TrackUtil { // Static access only. } - public static final MessageEmbed trackInfoEmbed(final AudioTrack track) { - Checks.notNull(track, "Track"); + public static final MessageEmbed trackInfoEmbed(final RequestedTrack queuedTrack) { + Checks.notNull(queuedTrack, "Track"); + final AudioTrack track = queuedTrack.getTrack(); final EmbedBuilder builder = new EmbedBuilder(); final AudioTrackInfo info = track.getInfo(); + final User requester = queuedTrack.getRequester().getUser(); builder.addField(StringUtil.sanitize(info.title), StringUtil.sanitize(info.author) + " - " + StringUtil.formatTime(track.getDuration()) + " - [View](" + info.uri + ")", false).build(); + builder.setFooter( + "Requested by " + StringUtil.sanitize(requester.getName()) + "#" + requester.getDiscriminator(), + requester.getAvatarUrl()); return builder.build(); } @@ -43,16 +50,20 @@ public final class TrackUtil { Checks.notNull(guild, "Guild"); final EmbedBuilder builder = new EmbedBuilder(); - final AudioTrack track = AudioUtil.getLoadedTrack(guild); + final AudioTrack track = AudioUtil.getLoadedTrack(guild).getTrack(); final AudioTrackInfo info = track.getInfo(); + final User requester = AudioUtil.getLoadedTrack(guild).getRequester().getUser(); builder.addField(StringUtil.sanitize(info.title), StringUtil.sanitize(info.author) + " - " + StringUtil.formatTime(track.getPosition()) + "/" + StringUtil.formatTime(track.getDuration()) + " - [View](" + info.uri + ")", false).build(); + builder.setFooter( + "Requested by " + StringUtil.sanitize(requester.getName()) + "#" + requester.getDiscriminator(), + requester.getAvatarUrl()); return builder.build(); } - public static final MessageEmbed trackListInfoEmbed(final List tracks, final boolean numbered) { + public static final MessageEmbed trackListInfoEmbed(final List tracks, final boolean numbered) { Checks.notNull(tracks, "Tracks"); Checks.notNull(numbered, "Numbered"); @@ -62,7 +73,7 @@ public final class TrackUtil { break; } - final AudioTrack track = tracks.get(i); + final AudioTrack track = tracks.get(i).getTrack(); final AudioTrackInfo info = track.getInfo(); if (numbered) { builder.addField( @@ -81,7 +92,7 @@ public final class TrackUtil { return builder.build(); } - public static final MessageEmbed pagedTrackListInfoEmbed(final List tracks, int page) { + public static final MessageEmbed pagedTrackListInfoEmbed(final List tracks, int page) { Checks.notNull(tracks, "Tracks"); Checks.notNull(page, "Page"); @@ -101,7 +112,7 @@ public final class TrackUtil { final int end = start + 10; for (int i = start; i < end && i < tracks.size(); i++) { - final AudioTrack track = tracks.get(i); + final AudioTrack track = tracks.get(i).getTrack(); final AudioTrackInfo info = track.getInfo(); builder.addField("**" + (i + 1) + ":** " + StringUtil.sanitize(info.title), StringUtil.sanitize(info.author) + " - " + StringUtil.formatTime(track.getDuration()) + " - [View](" + info.uri + ")", false); @@ -111,7 +122,7 @@ public final class TrackUtil { return builder.build(); } - public static final boolean doesGreaterPageExist(final List tracks, int page) { + public static final boolean doesGreaterPageExist(final List tracks, int page) { Checks.notNull(tracks, "Tracks"); Checks.notNull(page, "Page");