Improve music manager and add more debug messages

This commit is contained in:
anthorob committed 2022-05-27 18:16:22 -04:00
1 parent 7bfadb05f7
commit 8325256e5e
35 files changed
+554 -195

No files matched your search

@@ -18,6 +18,8 @@ import netneutrality.thread.BaseThreadFactory;
import netneutrality.thread.ShutdownThread; import netneutrality.thread.ShutdownThread;
import netneutrality.thread.ThreadManager; import netneutrality.thread.ThreadManager;
import netneutrality.utils.Settings; import netneutrality.utils.Settings;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -38,8 +40,12 @@ public class NetNeutrality {
options.setDebug(env.equals("dev")); options.setDebug(env.equals("dev"));
}); });
initJDA(); if ("dev".equals(env)) {
Configurator.setLevel("net.dv8tion.jda", Level.DEBUG);
}
DBController.init(); DBController.init();
initJDA();
CommandManager.init(); CommandManager.init();
MusicManager.initPlayerManager(); MusicManager.initPlayerManager();
jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler()); jda.addEventListener(new MessageReceivedHandler(), new EditHandler(), new ServerJoinHandler());
@@ -86,14 +86,14 @@ public class BitcoinPriceCommand extends AbstractCommand {
try { try {
WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request();
JSONObject json = http.getAsObject(); JSONObject json = http.getAsObject();
if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) {
t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); t.editMessage(String.format("Failed getting price of %s", crypto)).queue();
return; return;
} }
price = dollarFormat.format(json.getDouble(finalCurrency)); price = dollarFormat.format(json.getDouble(finalCurrency));
t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue();
} catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { } catch (JSONException | IllegalArgumentException | ArithmeticException e) {
t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); t.editMessage(String.format("Error getting price of %s!", crypto)).queue();
LogHandler.log(e); LogHandler.log(e);
} }
@@ -89,7 +89,7 @@ public class CryptoPriceCommand extends AbstractCommand {
try { try {
WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request();
JSONObject json = http.getAsObject(); JSONObject json = http.getAsObject();
if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) {
t.editMessage("Crypto doesn't exist.. yet").queue(); t.editMessage("Crypto doesn't exist.. yet").queue();
return; return;
} }
@@ -97,7 +97,7 @@ public class CryptoPriceCommand extends AbstractCommand {
price = dollarFormat.format(json.getDouble(finalCurrency)); price = dollarFormat.format(json.getDouble(finalCurrency));
t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue();
} catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { } catch (JSONException | IllegalArgumentException | ArithmeticException e) {
t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); t.editMessage(String.format("Error getting price of %s!", crypto)).queue();
LogHandler.log(e); LogHandler.log(e);
} }
@@ -86,14 +86,14 @@ public class EthereumPriceCommand extends AbstractCommand {
try { try {
WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request();
JSONObject json = http.getAsObject(); JSONObject json = http.getAsObject();
if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) {
t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); t.editMessage(String.format("Failed getting price of %s", crypto)).queue();
return; return;
} }
price = dollarFormat.format(json.getDouble(finalCurrency)); price = dollarFormat.format(json.getDouble(finalCurrency));
t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue();
} catch (IOException | JSONException | IllegalArgumentException e) { } catch (JSONException | IllegalArgumentException e) {
t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); t.editMessage(String.format("Error getting price of %s!", crypto)).queue();
LogHandler.log(e); LogHandler.log(e);
} }
@@ -86,14 +86,14 @@ public class LitecoinPriceCommand extends AbstractCommand {
try { try {
WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request(); WebModule http = new WebModule(String.format("%s?fsym=%s&tsyms=%s", baseURL, crypto, finalCurrency.toUpperCase())).request();
JSONObject json = http.getAsObject(); JSONObject json = http.getAsObject();
if (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error")) { if (json.isEmpty() || (json.has("Response") && json.getString("Response").equalsIgnoreCase("Error"))) {
t.editMessage(String.format("Failed getting price of %s", crypto)).queue(); t.editMessage(String.format("Failed getting price of %s", crypto)).queue();
return; return;
} }
price = dollarFormat.format(json.getDouble(finalCurrency)); price = dollarFormat.format(json.getDouble(finalCurrency));
t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue(); t.editMessage(String.format("The current price of %s in %s is %s", crypto, finalCurrency, price)).queue();
} catch (IOException | JSONException | IllegalArgumentException | ArithmeticException e) { } catch (JSONException | IllegalArgumentException | ArithmeticException e) {
t.editMessage(String.format("Error getting price of %s!", crypto)).queue(); t.editMessage(String.format("Error getting price of %s!", crypto)).queue();
LogHandler.log(e); LogHandler.log(e);
} }
@@ -57,7 +57,7 @@ public class BlacklistCommand extends AbstractCommand {
@Override @Override
public void execute(CommandContext context) { public void execute(CommandContext context) {
String[] args = context.getArgumentsAsArray(); String[] args = context.getArgumentsAsArray();
DBBlacklist controller = DBController.get("blacklist", DBBlacklist.class); DBBlacklist controller = DBController.get(DBBlacklist.class);
if (args.length > 0 && args.length < 3) { if (args.length > 0 && args.length < 3) {
String word = (args.length == 2 ? args[1] : ""); String word = (args.length == 2 ? args[1] : "");
@@ -79,8 +79,11 @@ public class DeleteQueueCommand extends AbstractMusicCommand {
int num = Integer.parseInt(context.getArg(0)); int num = Integer.parseInt(context.getArg(0));
if (num > 0) { if (num > 0) {
player.removeFromQueue(num); if (player.removeFromQueue(num)) {
context.reply("Removing track #%d from the queue", num); context.reply("Removed track #%d from the queue", num);
} else {
context.reply("Error while removing track #%d from the queue", num);
}
} else { } else {
context.reply("Number out of range"); context.reply("Number out of range");
} }
@@ -60,6 +60,10 @@ public class JoinCommand extends AbstractMusicCommand {
} }
VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel(); VoiceChannel vChannel = context.getGuildUser().getVoiceState().getChannel();
player.connect(vChannel); if (vChannel != null) {
player.connect(vChannel);
context.reply("Joining current voice channel");
}
} }
} }
@@ -50,6 +50,7 @@ public class LeaveCommand extends AbstractMusicCommand {
if (MusicUtils.checkIfConnected(player, context)) { if (MusicUtils.checkIfConnected(player, context)) {
player.leave(); player.leave();
context.reply("Leaving voice channel and clearing queue");
} }
} }
} }
@@ -12,8 +12,6 @@ import netneutrality.command.CommandUsage;
import netneutrality.core.context.CommandContext; import netneutrality.core.context.CommandContext;
import netneutrality.music.MusicManager; import netneutrality.music.MusicManager;
import java.util.concurrent.TimeUnit;
public class PlayCommand extends AbstractMusicCommand { public class PlayCommand extends AbstractMusicCommand {
@Override @Override
@@ -47,7 +45,6 @@ public class PlayCommand extends AbstractMusicCommand {
@Override @Override
public void execute(CommandContext context) { public void execute(CommandContext context) {
MusicManager player = MusicManager.get(context.getGuild()); MusicManager player = MusicManager.get(context.getGuild());
context.getMessage().delete().queueAfter(1, TimeUnit.SECONDS);
if (context.getArgs().length > 0) { if (context.getArgs().length > 0) {
player.play(context.getMessageText(), context, false, false); player.play(context.getMessageText(), context, false, false);
@@ -52,11 +52,14 @@ public class SkipCommand extends AbstractMusicCommand {
try { try {
int skips = Integer.parseInt(context.getArg(0)); int skips = Integer.parseInt(context.getArg(0));
player.skip(skips); player.skip(skips);
context.reply("Skipping %s track%s", skips, (skips > 1 ? "s" : ""));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
context.reply("Please enter how many track(s) to skip"); context.reply("Please enter how many track(s) to skip");
} }
} else { } else {
player.skip(1); player.skip(1);
context.reply("Skipping current track");
} }
} else { } else {
player.voteSkip(context); player.voteSkip(context);
@@ -46,6 +46,7 @@ public class StopCommand extends AbstractMusicCommand {
if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) { if (MusicUtils.checkIfConnected(player, context) && MusicUtils.isDj(player, context)) {
player.stopTrack(); player.stopTrack();
context.reply("Stopping current track");
} }
} }
} }
@@ -74,7 +74,7 @@ public class DatabaseCommand extends AbstractCommand {
if (args.length > 1) { if (args.length > 1) {
OLogMessage message = DBController.get("message", DBMessage.class).getMessage(args[1]); OLogMessage message = DBController.get(DBMessage.class).getMessage(args[1]);
if (message != null) { if (message != null) {
EmbedBuilder embed = new EmbedBuilder(); EmbedBuilder embed = new EmbedBuilder();
embed.setColor(Color.BLUE); embed.setColor(Color.BLUE);
@@ -88,7 +88,7 @@ public class DatabaseCommand extends AbstractCommand {
//TODO: cached user lol xd //TODO: cached user lol xd
User user = context.getJDA().getUserById(args[1]); User user = context.getJDA().getUserById(args[1]);
if (user != null) { if (user != null) {
List<OLogMessage> messages = DBController.get("message", DBMessage.class) List<OLogMessage> messages = DBController.get(DBMessage.class)
.getMessagesFromUser(user.getName(), context.getGuild().getName(), 10); .getMessagesFromUser(user.getName(), context.getGuild().getName(), 10);
EmbedBuilder embed = new EmbedBuilder(); EmbedBuilder embed = new EmbedBuilder();
embed.setColor(Color.BLUE); embed.setColor(Color.BLUE);
@@ -49,8 +49,8 @@ public class CommandManager {
commands.put(command.getCommandName(), command); commands.put(command.getCommandName(), command);
} }
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) { | InvocationTargetException | NoSuchMethodException | SecurityException e) {
e.printStackTrace(); LogHandler.log(e);
} }
} }
@@ -228,7 +228,7 @@ public class GuildManager {
public void checkAndLogMessage(Message message, Member member, TextChannel channel) { public void checkAndLogMessage(Message message, Member member, TextChannel channel) {
if (isLoggingEnabled()) { if (isLoggingEnabled()) {
ThreadManager.getExecutor("log-messages").submit(() -> DBController.get("message", DBMessage.class).log(this, channel, member, message)); ThreadManager.getExecutor("log-messages").submit(() -> DBController.get(DBMessage.class).log(this, channel, member, message));
} }
} }
@@ -24,6 +24,7 @@ import netneutrality.utils.UserFunction;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
public class CommandContext { public class CommandContext {
@@ -153,6 +154,18 @@ public class CommandContext {
} }
} }
public void replyToMessage(String msg) {
if (channel != null && channel.canTalk() && message != null) {
replyToMessage(new MessageBuilder(msg).build());
}
}
public void replyToMessage(Message msg) {
if (channel != null && channel.canTalk() && message != null) {
message.reply(msg).queue();
}
}
public void replyPrivate(String msg) { public void replyPrivate(String msg) {
replyPrivate(new MessageBuilder(msg).build()); replyPrivate(new MessageBuilder(msg).build());
} }
@@ -169,6 +182,22 @@ public class CommandContext {
user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue(); user.openPrivateChannel().flatMap(channel -> channel.sendMessageEmbeds(embeds)).queue();
} }
public void deleteMessage() {
if (message != null) {
message.delete().queueAfter(1, TimeUnit.SECONDS);
}
}
public boolean isMessageFromOwner() {
return member.isOwner();
}
public boolean isMessageFromCreator() {
String creatorId = Settings.getInstance().getCreatorId();
return creatorId.equals(member.getId());
}
public void dispatch(AbstractCommand command) { public void dispatch(AbstractCommand command) {
this.command = command; this.command = command;
//TODO: Add usage check //TODO: Add usage check
@@ -14,13 +14,6 @@ public abstract class AbstractController {
protected SessionFactory sessionFactory; protected SessionFactory sessionFactory;
/**
* The controller name to be used in {@link DBController#get(String controller, Class returnType)} method
*
* @return String
*/
public abstract String getControllerName();
public AbstractController() { public AbstractController() {
sessionFactory = SessionManager.getSessionFactory(); sessionFactory = SessionManager.getSessionFactory();
} }
@@ -8,86 +8,32 @@ package netneutrality.db;
*/ */
import netneutrality.core.SessionManager; import netneutrality.core.SessionManager;
import netneutrality.thread.ThreadManager;
import org.reflections.Reflections;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Set;
/**
* When creating a controller, all database actions must be executed in another thread using an executor. One is provided in the {@link ThreadManager} class
* A simple thread can't be used in this case because overlapping actions might happen and won't be executed.
*/
public class DBController { public class DBController {
/**
* A map that contains all the controllers currently loaded
*/
private final static HashMap<String, AbstractController> controllers = new HashMap<>();
private final static Logger logger = LoggerFactory.getLogger(DBController.class); private final static Logger logger = LoggerFactory.getLogger(DBController.class);
/** public static <T> T get(Class<T> returnType) {
* @param controller The name of the controller as defined in the {@link AbstractController#getControllerName()}'s method
* @return {@link AbstractController} The class with an AbstractController type
*/
@SuppressWarnings("unchecked")
public static <T> T get(String controller, Class<T> returnType) {
if (returnType == null) if (returnType == null)
throw new IllegalArgumentException("return type is null"); throw new IllegalArgumentException("return type is null");
if (controllers.isEmpty()) try {
init(); return returnType.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
if (controllers.containsKey(controller)) { throw new RuntimeException(e);
return (T) controllers.get(controller); }
} else
throw new RuntimeException("Error getting database controller");
} }
public static void shutdown() { public static void shutdown() {
SessionManager.shutdown(); SessionManager.shutdown();
} }
/**
* Optional, will be called if the method {@link #get(String, Class) get()} is used
*/
public static void init() { public static void init() {
if (controllers.isEmpty()) SessionManager.getSessionFactory();
loadControllers();
} }
/**
* Loads all the controllers which extends {@link AbstractController}
*/
private static void loadControllers() {
//TODO: to delete
logger.info("Loading databases controllers..");
Reflections reflections = new Reflections("netneutrality.db.controllers");
Set<Class<? extends AbstractController>> classes = reflections.getSubTypesOf(AbstractController.class);
for (Class<? extends AbstractController> s : classes) {
try {
if (Modifier.isAbstract(s.getModifiers())) {
continue;
}
AbstractController c = s.getConstructor().newInstance();
if (!controllers.containsKey(c.getControllerName())) {
controllers.put(c.getControllerName(), c);
logger.debug("Loaded controller: " + c.getControllerName());
}
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
e.printStackTrace();
}
}
}
} }
@@ -128,9 +128,4 @@ public class DBBlacklist extends AbstractController {
session.close(); session.close();
return blacklist; return blacklist;
} }
@Override
public String getControllerName() {
return "blacklist";
}
} }
@@ -96,10 +96,4 @@ public class DBMessage extends AbstractController {
return message.getMessage(); return message.getMessage();
} }
@Override
public String getControllerName() {
return "message";
}
} }
@@ -46,8 +46,8 @@ public class EditHandler extends ListenerAdapter {
TextChannel channel = event.getGuild().getTextChannelById(guildEntity.getLogChannel()); TextChannel channel = event.getGuild().getTextChannelById(guildEntity.getLogChannel());
if (channel != null) { if (channel != null) {
String originalMessage = DBController.get("message", DBMessage.class).getMessageString(event.getMessage().getId()); String originalMessage = DBController.get(DBMessage.class).getMessageString(event.getMessage().getId());
DBController.get("message", DBMessage.class).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay()); DBController.get(DBMessage.class).logEdit(event.getMessage().getId(), event.getMessage().getContentDisplay());
channel.sendMessageEmbeds(MessageFunction.buildEditMessage(event.getMember(), event.getMessage(), originalMessage)).queue(); channel.sendMessageEmbeds(MessageFunction.buildEditMessage(event.getMember(), event.getMessage(), originalMessage)).queue();
} }
@@ -2,6 +2,7 @@ package netneutrality.http;
import io.sentry.Breadcrumb; import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import netneutrality.core.LogHandler;
import okhttp3.*; import okhttp3.*;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@@ -144,11 +145,17 @@ public class WebModule {
/** /**
* @return the response as a JSONObject * @return the response as a JSONObject
*/ */
public JSONObject getAsObject() throws JSONException, IOException { public JSONObject getAsObject() {
if (response == null) if (response == null)
throw new RuntimeException("Request has not been sent"); throw new RuntimeException("Request has not been sent");
return new JSONObject(response.body().string()); try {
ResponseBody body = response.body();
return new JSONObject(body.string());
} catch (IOException | NullPointerException e) {
LogHandler.log(e);
return new JSONObject();
}
} }
/** /**
@@ -21,16 +21,14 @@ import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.entities.VoiceChannel;
import netneutrality.core.GuildManager; import netneutrality.core.GuildManager;
import netneutrality.core.LogHandler;
import netneutrality.core.context.CommandContext; import netneutrality.core.context.CommandContext;
import netneutrality.exceptions.CommandErrorException; import netneutrality.music.loadable.LoadableSong;
import netneutrality.thread.MusicPlayerAutoDisconnectThread; import netneutrality.thread.MusicPlayerAutoDisconnectThread;
import netneutrality.thread.ThreadManager; import netneutrality.thread.ThreadManager;
import netneutrality.utils.MessageFunction; import netneutrality.utils.MessageFunction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
@@ -45,21 +43,19 @@ public class MusicManager {
private final static Map<String, MusicManager> managers = new ConcurrentHashMap<>(); private final static Map<String, MusicManager> managers = new ConcurrentHashMap<>();
private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED); private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED);
private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
private final Guild guild; private final Guild guild;
private final AudioPlayer player; private final AudioPlayer player;
private final AudioPlayerManager playerManager;
private final TrackScheduler scheduler; private final TrackScheduler scheduler;
private ScheduledFuture<?> autoDisconnectThread; private ScheduledFuture<?> autoDisconnectThread;
private final int baseVolume; private final int baseVolume;
private MusicManager(Guild guild) { private MusicManager(Guild guild) {
this.guild = guild; this.guild = guild;
this.playerManager = new DefaultAudioPlayerManager();
this.player = playerManager.createPlayer(); this.player = playerManager.createPlayer();
this.scheduler = new TrackScheduler(player, guild); this.scheduler = new TrackScheduler(player, guild);
this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME)); this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_VOLUME));
AudioSourceManagers.registerRemoteSources(playerManager);
guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player)); guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player));
player.addListener(scheduler); player.addListener(scheduler);
@@ -75,6 +71,8 @@ public class MusicManager {
} }
public static void initPlayerManager() { public static void initPlayerManager() {
AudioSourceManagers.registerRemoteSources(playerManager);
YoutubeHttpContextFilter.setPAPISID(netneutrality.utils.Settings.getInstance().get("BOT_PAPISID", "")); YoutubeHttpContextFilter.setPAPISID(netneutrality.utils.Settings.getInstance().get("BOT_PAPISID", ""));
YoutubeHttpContextFilter.setPSID(netneutrality.utils.Settings.getInstance().get("BOT_PSID", "")); YoutubeHttpContextFilter.setPSID(netneutrality.utils.Settings.getInstance().get("BOT_PSID", ""));
} }
@@ -85,6 +83,7 @@ public class MusicManager {
public synchronized void connect(VoiceChannel vChannel) { public synchronized void connect(VoiceChannel vChannel) {
if (vChannel != null && !isConnectedTo(vChannel)) { if (vChannel != null && !isConnectedTo(vChannel)) {
logger.debug("Guild {}: connecting to voice channel {}", vChannel.getGuild().getId(), vChannel.getId());
guild.getAudioManager().openAudioConnection(vChannel); guild.getAudioManager().openAudioConnection(vChannel);
guild.getAudioManager().setSelfDeafened(true); guild.getAudioManager().setSelfDeafened(true);
player.setVolume(baseVolume); player.setVolume(baseVolume);
@@ -124,6 +123,7 @@ public class MusicManager {
public synchronized void leave() { public synchronized void leave() {
if (isConnected()) { if (isConnected()) {
logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId());
player.stopTrack(); player.stopTrack();
guild.getAudioManager().closeAudioConnection(); guild.getAudioManager().closeAudioConnection();
} }
@@ -155,6 +155,100 @@ public class MusicManager {
public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) { public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) {
Member member = context.getGuildUser(); Member member = context.getGuildUser();
TextChannel channel = context.getChannel(); TextChannel channel = context.getChannel();
logger.debug("Guild {}: request to play by user {}, string=[{}]", guild.getId(), context.getGuildUser().getId(), url);
if (member.getVoiceState() == null) {
context.deleteMessage();
return;
}
if (!member.getVoiceState().inVoiceChannel()) {
context.reply("You are not in a voice channel");
context.deleteMessage();
return;
}
VoiceChannel vChannel = member.getVoiceState().getChannel();
if (needToBeConnected && !isConnectedTo(vChannel)) {
context.reply("The player is not in your voice channel");
context.deleteMessage();
return;
}
if (!isConnectedTo(vChannel)) {
connect(vChannel);
}
String identifier = SourceFinder.getIdentifier(url);
scheduler.getTopicManager().attachTextChannel(channel);
if (identifier != null) {
playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() {
@Override
public void trackLoaded(AudioTrack audioTrack) {
logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier);
context.deleteMessage();
scheduler.getQueueManager().queue(audioTrack, member);
if (!silent) {
//context.replyToMessage("Added track to queue");
context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier));
}
}
@Override
public void playlistLoaded(AudioPlaylist audioPlaylist) {
logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier);
context.deleteMessage();
if (audioPlaylist.isSearchResult()) {
AudioTrack track = audioPlaylist.getTracks().get(0);
scheduler.getQueueManager().queue(track, member);
if (!silent) {
//context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build());
context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier())));
}
} else {
if (!silent) {
//context.replyToMessage("Added playlist to queue");
context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier));
}
for (AudioTrack track : audioPlaylist.getTracks()) {
synchronized (scheduler.getQueueManager().getQueue()) {
scheduler.getQueueManager().queue(track, member);
}
}
}
}
@Override
public void noMatches() {
logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier);
context.replyToMessage("No matches found");
}
@Override
public void loadFailed(FriendlyException e) {
logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e);
context.replyToMessage("Failed to load track: " + e.getMessage());
}
});
} else {
context.replyToMessage("No source found to play the given url");
}
}
public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) {
Member member = context.getGuildUser();
TextChannel channel = context.getChannel();
if (member.getVoiceState() == null) { if (member.getVoiceState() == null) {
return; return;
@@ -175,72 +269,89 @@ public class MusicManager {
connect(vChannel); connect(vChannel);
} }
String identifier = SourceFinder.getIdentifier(url);
scheduler.getTopicManager().attachTextChannel(channel); scheduler.getTopicManager().attachTextChannel(channel);
boolean fromOnlineSource = songs.size() > 1;
if (identifier != null) { for (LoadableSong song : songs) {
String identifier = SourceFinder.getIdentifier(song.name());
playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() { if (identifier != null) {
playerManager.loadItemOrdered(this, identifier, new AudioLoadResultHandler() {
@Override
public void trackLoaded(AudioTrack track) {
if (!fromOnlineSource) {
logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier);
context.deleteMessage();
@Override scheduler.getQueueManager().queue(track, member);
public void trackLoaded(AudioTrack audioTrack) {
logger.debug("Found results for identifier: {}", identifier);
scheduler.getQueueManager().queue(audioTrack, member);
if (!silent) { if (!silent) {
channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(audioTrack, member, identifier)).queue(); //context.replyToMessage("Added track to queue");
} context.reply(MessageFunction.buildAddingTrackMessage(track, member, identifier));
}
@Override
public void playlistLoaded(AudioPlaylist audioPlaylist) {
if (identifier.startsWith("ytsearch:")) {
AudioTrack track = audioPlaylist.getTracks().get(0);
logger.debug("Found results for identifier: {}", identifier);
scheduler.getQueueManager().queue(track, member);
if (!silent) {
channel.sendMessageEmbeds(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier()))).queue();
}
} else {
logger.debug("Found results for playlist identifier: {}", identifier);
if (!silent) {
channel.sendMessageEmbeds(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, member, identifier)).queue();
}
for (AudioTrack track : audioPlaylist.getTracks()) {
synchronized (scheduler.getQueueManager().getQueue()) {
scheduler.getQueueManager().queue(track, member);
} }
} }
} }
}
@Override @Override
public void noMatches() { public void playlistLoaded(AudioPlaylist playlist) {
context.reply("No matches found"); logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier);
}
@Override if (!playlist.getTracks().isEmpty()) {
public void loadFailed(FriendlyException e) { context.deleteMessage();
context.reply("Failed to load track: " + e.getMessage());
LogHandler.log(e); if (playlist.isSearchResult()) {
} AudioTrack track = playlist.getTracks().get(0);
scheduler.getQueueManager().queue(track, member);
if (!silent && !fromOnlineSource) {
//context.replyToMessage(new MessageBuilder("Added track to queue: ").append(String.format("https://youtu.be/%s", track.getIdentifier())).build());
context.reply(MessageFunction.buildAddingTrackMessage(track, member, String.format("https://youtu.be/%s", track.getIdentifier())));
}
} else {
if (!silent && !fromOnlineSource) {
//context.replyToMessage("Added playlist to queue");
context.reply(MessageFunction.buildAddingPlaylistMessage(playlist, member, identifier));
}
for (AudioTrack track : playlist.getTracks()) {
synchronized (scheduler.getQueueManager().getQueue()) {
scheduler.getQueueManager().queue(track, member);
}
}
}
} else {
context.replyToMessage("Playlist is empty");
}
}
@Override
public void noMatches() {
logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier);
if (fromOnlineSource) {
//TODO:
}
context.replyToMessage("No matches found");
}
@Override
public void loadFailed(FriendlyException e) {
logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e);
context.replyToMessage("Failed to load track: " + e.getMessage());
}
});
} else {
context.replyToMessage("No source found to play the given url");
}
});
} else {
throw new CommandErrorException("No source found to play the given url", context, null);
} }
} }
public synchronized void removeFromQueue(int num) { public synchronized boolean removeFromQueue(int index) {
if (num == 1) { return scheduler.getQueueManager().removeFromQueue(index);
skip(1);
} else {
scheduler.getQueueManager().removeFromQueue(num);
}
} }
public synchronized void stopTrack() { public synchronized void stopTrack() {
@@ -253,6 +364,7 @@ public class MusicManager {
nbTrack = 1; nbTrack = 1;
} }
logger.debug("Guild {}: skipping tracks, toSkip={}", guild.getId(), nbTrack);
scheduler.getQueueManager().skipAndPlay(nbTrack); scheduler.getQueueManager().skipAndPlay(nbTrack);
} else { } else {
leave(); leave();
@@ -278,13 +390,14 @@ public class MusicManager {
if (connected > 2) { if (connected > 2) {
double needed = connected / 2.1; double needed = connected / 2.1;
info.toggleSkip(context.getGuildUser()); info.addSkip(context.getGuildUser());
logger.debug("VoteSkip: guild={}, connected={}, needed={}, skips={}, user={}", context.getGuild().getId(), connected, needed, info.getSkips().size(), context.getGuildUser().getId());
if (info.getSkips().size() > needed) { if (info.getSkips().size() > needed) {
context.reply("Skipping current track: %s", info.getTrack().getInfo().title); context.reply("Skipping current track: %s", info.getTrack().getInfo().title);
skip(1); skip(1);
} else { } else {
context.reply("Current skips: %d/%d", info.getSkips().size(), (int) Math.ceil(needed)); context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed));
} }
} else { } else {
@@ -9,6 +9,8 @@ import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*; import java.util.*;
import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingDeque;
@@ -20,6 +22,7 @@ public class QueueManager {
private final AudioTrack track; private final AudioTrack track;
private final Member member; private final Member member;
private final Set<String> skips; private final Set<String> skips;
private final Logger logger = LoggerFactory.getLogger(QueueManager.class);
public TrackInfo(AudioTrack track, Member member) { public TrackInfo(AudioTrack track, Member member) {
this.track = track; this.track = track;
@@ -35,11 +38,21 @@ public class QueueManager {
return skips; return skips;
} }
public void toggleSkip(Member member) { public void addSkip(Member member) {
if (!hasSkip(member)) if (!hasSkip(member)) {
logger.debug("VoteSkip: user={}, skip doesn't exist, before={}, after={}", member.getId(), skips.size(), skips.size() + 1);
skips.add(member.getId()); skips.add(member.getId());
else }
}
public void toggleSkip(Member member) {
if (hasSkip(member)) {
logger.debug("VoteSkip: user={}, skip already exist, before={}, after={}", member.getId(), skips.size(), skips.size() - 1);
skips.remove(member.getId()); skips.remove(member.getId());
} else {
logger.debug("VoteSkip: user={}, skip doesn't exist, before={}, after={}", member.getId(), skips.size(), skips.size() + 1);
skips.add(member.getId());
}
} }
public boolean hasSkip(Member member) { public boolean hasSkip(Member member) {
@@ -73,6 +86,7 @@ public class QueueManager {
} }
} }
private final Logger logger = LoggerFactory.getLogger(QueueManager.class);
private final AudioPlayer player; private final AudioPlayer player;
private final Guild guild; private final Guild guild;
private final Deque<TrackInfo> queue; private final Deque<TrackInfo> queue;
@@ -120,7 +134,8 @@ public class QueueManager {
} }
if (player.getPlayingTrack() == null) { if (player.getPlayingTrack() == null) {
player.startTrack(queue.peek().getTrack(), false); AudioTrack toPlay = (queue.peek() == null ? null : queue.peek().getTrack());
player.startTrack(toPlay, true);
} }
} }
} }
@@ -128,9 +143,15 @@ public class QueueManager {
public void nextTrack(AudioPlayer player) { public void nextTrack(AudioPlayer player) {
synchronized (queue) { synchronized (queue) {
TrackInfo last = queue.poll(); TrackInfo last = queue.poll();
TrackInfo next = queue.peek();
if (queue.peek() != null) { if (next != null) {
player.startTrack(queue.peek().getTrack(), false); if (last != null && last.getTrack().equals(next.getTrack())) {
logger.debug("Guild {}: duplicate track in queue found, skipping to next. last={}, next={}", guild.getId(), last.getTrack().getIdentifier(), next.getTrack().getIdentifier());
nextTrack(player);
} else {
player.startTrack(next.getTrack(), false);
}
} else { } else {
player.stopTrack(); player.stopTrack();
} }
@@ -159,7 +180,8 @@ public class QueueManager {
public void shuffle() { public void shuffle() {
synchronized (queue) { synchronized (queue) {
if (queue.size() > 2) { if (queue.size() > 3) {
logger.debug("Guild {}: shuffling queue", guild.getId());
TrackInfo current = queue.poll(); TrackInfo current = queue.poll();
ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); ArrayList<TrackInfo> newQueue = new ArrayList<>(queue);
@@ -174,13 +196,25 @@ public class QueueManager {
} }
} }
protected void removeFromQueue(int index) { protected boolean removeFromQueue(int index) {
synchronized (queue) { synchronized (queue) {
ArrayList<TrackInfo> newQueue = new ArrayList<>(queue); if (queue.size() > 0 && index <= queue.size()) {
newQueue.remove(index - 1); logger.debug("Guild {}: removing index {} from queue", guild.getId(), index - 1);
queue.clear(); if (index == 1) {
queue.addAll(newQueue); skipAndPlay(1);
return true;
}
ArrayList<TrackInfo> newQueue = new ArrayList<>(queue);
newQueue.remove(index - 1);
queue.clear();
queue.addAll(newQueue);
return true;
}
return false;
} }
} }
@@ -9,22 +9,18 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.core.GuildManager; import netneutrality.core.GuildManager;
import netneutrality.thread.ThreadManager;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class TopicManager { public class TopicManager {
private final ScheduledExecutorService service;
private final Guild guild; private final Guild guild;
private TextChannel channel; private TextChannel channel;
private String originalTopic; private String originalTopic;
public TopicManager(Guild guild) { public TopicManager(Guild guild) {
this.guild = guild; this.guild = guild;
this.service = (ScheduledExecutorService) ThreadManager.getExecutor("topic-management", ThreadManager.ExecutorType.SCHEDULED);
} }
public Guild getGuild() { public Guild getGuild() {
@@ -59,16 +55,24 @@ public class TopicManager {
if (isEnabled() && channel != null) { if (isEnabled() && channel != null) {
if (track == null) { if (track == null) {
LogManager.getLogger(TopicManager.class).debug("Resetting topic for channel [{}] in guild [{}]", channel.getId(), guild.getId()); LogManager.getLogger(TopicManager.class).debug("Guild {}: Resetting topic for channel {}", guild.getId(), channel.getId());
channel.getManager().setTopic(originalTopic).queueAfter(3, TimeUnit.SECONDS, service); channel.getManager().setTopic(originalTopic).queueAfter(5, TimeUnit.SECONDS);
} else { } else {
channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(3, TimeUnit.SECONDS, service); LogManager.getLogger(TopicManager.class).debug("Guild {}: Setting topic for channel {} to [{}]", guild.getId(), channel.getId(), track.getInfo().title);
channel.getManager().setTopic(":speaker: Now playing: " + track.getInfo().title).queueAfter(5, TimeUnit.SECONDS);
} }
} }
} }
public void sendMessageToChannel(String msg) {
if (channel != null) {
channel.sendMessage(msg).queue();
}
}
private boolean isEnabled() { private boolean isEnabled() {
return "1".equals(GuildManager.getManager(guild).getSetting(GuildManager.Settings.MUSIC_TOPIC)); // rate limiting too much
return false;
} }
} }
@@ -55,16 +55,21 @@ public class TrackScheduler extends AudioEventAdapter {
@Override @Override
public void onTrackStart(AudioPlayer player, AudioTrack track) { public void onTrackStart(AudioPlayer player, AudioTrack track) {
logger.debug("Starting track on guild {}: {}", guild.getId(), track.getIdentifier()); logger.debug("Guild {}: starting track: {}", guild.getId(), track.getIdentifier());
topicManager.updateTopic(track); topicManager.updateTopic(track);
} }
@Override @Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
logger.debug("Guild {}: currently playing track ended: {}", guild.getId(), track.getIdentifier());
if (endReason == AudioTrackEndReason.LOAD_FAILED) {
logger.debug("Guild {}: failed loading track: {}", guild.getId(), track.getIdentifier());
}
// check if mayStartNext // check if mayStartNext
if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) {
queueManager.nextTrack(player); queueManager.nextTrack(player);
} }
if (endReason == AudioTrackEndReason.STOPPED) { if (endReason == AudioTrackEndReason.STOPPED) {
@@ -84,13 +89,16 @@ public class TrackScheduler extends AudioEventAdapter {
@Override @Override
public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) { public void onTrackException(AudioPlayer player, AudioTrack track, FriendlyException exception) {
logger.debug("Guild {}: exception while playing track [{}]: {}", guild.getId(), track.getIdentifier(), exception.getMessage());
topicManager.updateTopic(null); topicManager.updateTopic(null);
topicManager.getTextChannel().sendMessage("Error while playing track: " + track.getInfo().title).queue(); topicManager.sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage());
} }
@Override @Override
public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) { public void onTrackStuck(AudioPlayer player, AudioTrack track, long thresholdMs) {
logger.debug("Guild {}: currently playing track is stuck: {}", guild.getId(), track.getIdentifier());
topicManager.updateTopic(null); topicManager.updateTopic(null);
topicManager.sendMessageToChannel("Current track is stuck, skipping to next");
queueManager.nextTrack(player); queueManager.nextTrack(player);
} }
} }
@@ -0,0 +1,42 @@
package netneutrality.music.loadable;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class AppleMostPlayed implements LoadableMusicSource {
@Override
public String url() {
return "https://rss.applemarketingtools.com/api/v2/ca/music/most-played/25/songs.json";
}
@Override
public List<LoadableSong> parse(JSONObject obj) {
List<LoadableSong> songs = new ArrayList<>();
JSONArray results = obj.getJSONObject("feed").getJSONArray("results");
results.forEach(o -> {
JSONObject song = (JSONObject) o;
String artist = song.getString("artistName");
String songName = song.getString("name");
String artwork = song.getString("artworkUrl100");
songs.add(new LoadableSong(artist, songName, artwork));
});
return songs;
}
@Override
public String getIdentifier() {
return "apple";
}
}
@@ -0,0 +1,40 @@
package netneutrality.music.loadable;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import java.time.OffsetDateTime;
import java.util.List;
public class CachedSource {
private final LoadableMusicSource source;
private OffsetDateTime lastAccess;
private final List<LoadableSong> songs;
public CachedSource(LoadableMusicSource source, List<LoadableSong> songs) {
this.source = source;
this.lastAccess = OffsetDateTime.now();
this.songs = songs;
}
public List<LoadableSong> getSongs() {
return songs;
}
public OffsetDateTime getLastAccess() {
return lastAccess;
}
public LoadableMusicSource getSource() {
return source;
}
public void updateAccessTime() {
this.lastAccess = OffsetDateTime.now();
}
}
@@ -0,0 +1,26 @@
package netneutrality.music.loadable;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import org.json.JSONObject;
import java.util.List;
public interface LoadableMusicSource {
String url();
List<LoadableSong> parse(JSONObject obj);
String getIdentifier();
}
@@ -0,0 +1,19 @@
package netneutrality.music.loadable;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
public record LoadableSong(String artist, String name, String artworkUrl) {
@Override
public String toString() {
return "LoadableSong{" +
"artist='" + artist + '\'' +
", name='" + name + '\'' +
", artworkUrl='" + artworkUrl + '\'' +
'}';
}
}
@@ -0,0 +1,59 @@
package netneutrality.music.loadable;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import netneutrality.http.WebModule;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LoadableSourceManager {
private final Logger logger = LoggerFactory.getLogger(LoadableSourceManager.class);
private static final Map<String, CachedSource> cache = new HashMap<>();
public CachedSource get(LoadableMusicSource source) {
if (cache.containsKey(source.getIdentifier())) {
CachedSource cachedSource = cache.get(source.getIdentifier());
if (OffsetDateTime.now().isAfter(cachedSource.getLastAccess().plusHours(4))) {
cachedSource.getSongs().clear();
cachedSource.getSongs().addAll(loadFromUrl(source));
cachedSource.updateAccessTime();
}
return cachedSource;
} else {
List<LoadableSong> songs = loadFromUrl(source);
CachedSource newCachedSource = new CachedSource(source, songs);
cache.put(source.getIdentifier(), newCachedSource);
return newCachedSource;
}
}
private List<LoadableSong> loadFromUrl(LoadableMusicSource source) {
WebModule web = new WebModule(source.url());
JSONObject obj = web.request().getAsObject();
if (obj == null)
return Collections.emptyList();
List<LoadableSong> songs = source.parse(obj);
Collections.shuffle(songs);
return songs;
}
}
@@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.entities.VoiceChannel;
import netneutrality.NetNeutrality; import netneutrality.NetNeutrality;
import netneutrality.music.MusicManager; import netneutrality.music.MusicManager;
import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
@@ -29,8 +30,10 @@ public class MusicPlayerAutoDisconnectThread implements Runnable {
if (channel != null) { if (channel != null) {
List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList(); List<Member> members = channel.getMembers().stream().filter(member -> !member.getId().equals(NetNeutrality.getSelf().getId())).toList();
if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) if (members.size() == 0 || manager.getScheduler().getQueueManager().getQueue().isEmpty()) {
LoggerFactory.getLogger(MusicPlayerAutoDisconnectThread.class).debug("Guild {}: auto-disconnect player from voice channel: {}", guild.getId(), channel.getId());
manager.leave(); manager.leave();
}
} }
} }
} }
@@ -9,6 +9,7 @@ package netneutrality.utils;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack; import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.*;
import netneutrality.command.AbstractCommand; import netneutrality.command.AbstractCommand;
@@ -69,7 +70,6 @@ public class MessageFunction {
message.setTitle("Currently playing:"); message.setTitle("Currently playing:");
message.setColor(Color.BLUE); message.setColor(Color.BLUE);
message.addField("Track title: ", current.getInfo().title, false); message.addField("Track title: ", current.getInfo().title, false);
message.addField("Uploaded by: ", current.getInfo().author, false);
message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false); message.addField("Duration: ", DurationFormatUtils.formatDuration(current.getPosition(), "**HH:mm:ss**", true) + " / " + DurationFormatUtils.formatDuration(current.getDuration(), "**HH:mm:ss**", true), false);
message.setFooter("Requested by " + requester.getEffectiveName(), requester.getAvatarUrl()); message.setFooter("Requested by " + requester.getEffectiveName(), requester.getAvatarUrl());
message.setTimestamp(OffsetDateTime.now()); message.setTimestamp(OffsetDateTime.now());
@@ -84,7 +84,6 @@ public class MessageFunction {
message.setTitle("Adding track to queue.."); message.setTitle("Adding track to queue..");
message.setColor(Color.BLUE); message.setColor(Color.BLUE);
message.addField("Track title: ", track.getInfo().title, false); message.addField("Track title: ", track.getInfo().title, false);
message.addField("Uploaded by: ", track.getInfo().author, false);
message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false); message.addField("Duration: ", DurationFormatUtils.formatDuration(track.getDuration(), "**HH:mm:ss**", true), false);
message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl()); message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl());
message.setTimestamp(OffsetDateTime.now()); message.setTimestamp(OffsetDateTime.now());
@@ -111,15 +110,17 @@ public class MessageFunction {
AudioTrack current = manager.getCurrentlyPlaying(); AudioTrack current = manager.getCurrentlyPlaying();
EmbedBuilder message = new EmbedBuilder(); EmbedBuilder message = new EmbedBuilder();
message.setTitle("Current queue (showing max 10 items):"); message.setTitle("Current queue (showing 10 out of " + tracks.size() + " items):");
message.setColor(Color.BLUE); message.setColor(Color.BLUE);
int index = 0; int index = 0;
for (AudioTrack track : tracks) { for (AudioTrack track : tracks) {
if (track.getInfo().title.equals(current.getInfo().title) && currentlyPlaying) { AudioTrackInfo info = track.getInfo();
message.addField("Track #" + ++index + " (Currently playing)", track.getInfo().title, false);
if (current != null && current.getInfo().title.equals(info.title) && currentlyPlaying) {
message.addField("Track #" + ++index + " (Currently playing)", info.title, false);
} else { } else {
message.addField("Track #" + ++index, track.getInfo().title, false); message.addField("Track #" + ++index, info.title, false);
} }
if (index == 10) break; if (index == 10) break;
@@ -41,7 +41,7 @@ public class MusicUtils {
if (UserFunction.isAdmin(context.getGuildUser()) || manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) { if (UserFunction.isAdmin(context.getGuildUser()) || manager.getRequesterOfCurrentTrack().getId().equals(context.getGuildUser().getId())) {
return true; return true;
} else { } else {
context.reply("You are not powerful enough, scrub"); context.reply("You're not powerful enough, scrub");
return false; return false;
} }
} }
@@ -0,0 +1,31 @@
package netneutrality.music;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import netneutrality.music.loadable.AppleMostPlayed;
import netneutrality.music.loadable.CachedSource;
import netneutrality.music.loadable.LoadableSong;
import netneutrality.music.loadable.LoadableSourceManager;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
public class LoadableSourceTest {
@Test
public void getAppleMostPlayed() {
LoadableSourceManager loadableSourceManager = new LoadableSourceManager();
CachedSource cachedSource = loadableSourceManager.get(new AppleMostPlayed());
System.out.println(cachedSource.getLastAccess());
System.out.println(cachedSource.getSongs());
assertTrue(cachedSource.getSongs().size() > 0);
}
}