Refactored music manager

This commit is contained in:
anthorob committed 2022-08-26 11:08:28 -04:00
1 parent 02c1eab6e3
commit 64dd0da604
29 files changed
+484 -424

No files matched your search

@@ -58,6 +58,7 @@ public class NetNeutrality {
}
public static void initJDA() {
// When upgrading JDA -> GatewayIntent.MESSAGE_CONTENT
try {
jda = JDABuilder
.createDefault(Settings.getInstance().get("BOT_TOKEN"))
@@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.core.GuildManager;
import netneutrality.db.GSettings;
import netneutrality.utils.UserFunction;
public abstract class AbstractMusicCommand extends AbstractCommand {
@@ -27,7 +28,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand {
@Override
public boolean canBeExecutedBy(Guild guild, Member member) {
String roleDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_ROLE);
String roleDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_ROLE);
if (roleDb != null && !roleDb.isEmpty()) {
if (UserFunction.isAdmin(member)) {
@@ -37,7 +38,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand {
Role neededRole = guild.getRoleById(roleDb);
if (neededRole == null) {
// Role doesn't exist on guild anymore, remove from db
GuildManager.getManager(guild).setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null);
GuildManager.getManager(guild).setSettingValue(GSettings.MUSIC_ROLE, null);
return true;
}
@@ -49,7 +50,7 @@ public abstract class AbstractMusicCommand extends AbstractCommand {
@Override
public boolean canBeExecutedFrom(Guild guild, TextChannel channel) {
String channelDb = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_CHANNEL);
String channelDb = GuildManager.getManager(guild).getSetting(GSettings.MUSIC_CHANNEL);
if (channelDb != null && !channelDb.isEmpty()) {
return channelDb.equals(channel.getId());
@@ -13,6 +13,7 @@ import netneutrality.command.CommandType;
import netneutrality.command.CommandUsage;
import netneutrality.core.GuildManager;
import netneutrality.core.context.CommandContext;
import netneutrality.db.GSettings;
import netneutrality.music.MusicManager;
import java.util.Arrays;
@@ -66,7 +67,7 @@ public class ConfigureCommand extends AbstractCommand {
// Role for music commands
if (context.getArgument(0).equals("music-role")) {
if (args.length == 1) {
String roleDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE);
String roleDb = guildManager.getSetting(GSettings.MUSIC_ROLE);
Role role = null;
if (!roleDb.isEmpty()) {
role = context.getGuild().getRoleById(roleDb);
@@ -78,8 +79,8 @@ public class ConfigureCommand extends AbstractCommand {
if (args.length == 2) {
if (context.getArgument(1).equals("reset")) {
if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_ROLE).isEmpty()) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, null);
if (!guildManager.getSetting(GSettings.MUSIC_ROLE).isEmpty()) {
guildManager.setSettingValue(GSettings.MUSIC_ROLE, null);
}
context.reply("Successful reset of the role");
@@ -89,7 +90,7 @@ public class ConfigureCommand extends AbstractCommand {
if (roles.size() == 1) {
Role role = roles.get(0);
if (role.getGuild().getId().equals(context.getGuild().getId())) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_ROLE, role.getId());
guildManager.setSettingValue(GSettings.MUSIC_ROLE, role.getId());
context.reply("Successfully set %s as the role needed for music command", role.getAsMention());
}
}
@@ -99,7 +100,7 @@ public class ConfigureCommand extends AbstractCommand {
// Role for music commands
if (context.getArgument(0).equals("music-channel")) {
if (args.length == 1) {
String channelDb = guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL);
String channelDb = guildManager.getSetting(GSettings.MUSIC_CHANNEL);
TextChannel channel = null;
if (!channelDb.isEmpty()) {
channel = context.getGuild().getTextChannelById(channelDb);
@@ -111,8 +112,8 @@ public class ConfigureCommand extends AbstractCommand {
if (args.length == 2) {
if (context.getArgument(1).equals("reset")) {
if (!guildManager.getSetting(GuildManager.GSettings.MUSIC_CHANNEL).isEmpty()) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, null);
if (!guildManager.getSetting(GSettings.MUSIC_CHANNEL).isEmpty()) {
guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, null);
}
context.reply("Successful reset of the channel");
@@ -122,7 +123,7 @@ public class ConfigureCommand extends AbstractCommand {
if (channels.size() == 1) {
TextChannel channel = channels.get(0);
if (channel.getGuild().getId().equals(context.getGuild().getId())) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_CHANNEL, channel.getId());
guildManager.setSettingValue(GSettings.MUSIC_CHANNEL, channel.getId());
context.reply("Successfully set %s as the channel required to execute music command", channel.getAsMention());
}
}
@@ -132,7 +133,7 @@ public class ConfigureCommand extends AbstractCommand {
// Default volume for music player
if (context.getArgument(0).equals("music-volume")) {
if (args.length == 1) {
int volume = Integer.parseInt(guildManager.getSetting(GuildManager.GSettings.MUSIC_VOLUME));
int volume = Integer.parseInt(guildManager.getSetting(GSettings.MUSIC_VOLUME));
context.reply("Default volume for music player: %d", volume);
context.reply("Set using 'conf music-volume <value between 0 and 100>'");
@@ -143,7 +144,7 @@ public class ConfigureCommand extends AbstractCommand {
int volume = Integer.parseInt(args[1]);
if (volume > 0 && volume <= 100) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_VOLUME, String.valueOf(volume));
guildManager.setSettingValue(GSettings.MUSIC_VOLUME, String.valueOf(volume));
MusicManager.get(context.getGuild()).setVolume(volume);
context.reply("Default volume for music player is now %d", volume);
@@ -159,7 +160,7 @@ public class ConfigureCommand extends AbstractCommand {
// Music topic change
if (context.getArgument(0).equals("music-topic")) {
if (args.length == 1) {
boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC));
boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC));
context.reply("Set currently playing track in text channel topic: %s", (enabled ? "enabled" : "disabled"));
context.reply("Use 'conf music-topic 0/1' to toggle between states (0 = disabled, 1 = enabled).");
@@ -167,9 +168,9 @@ public class ConfigureCommand extends AbstractCommand {
if (args.length == 2) {
String str = args[1];
boolean enabled = "1".equals(guildManager.getSetting(GuildManager.GSettings.MUSIC_TOPIC));
boolean enabled = "1".equals(guildManager.getSetting(GSettings.MUSIC_TOPIC));
if (str.equals("0") || str.equals("1")) {
guildManager.setSettingValue(GuildManager.GSettings.MUSIC_TOPIC, str);
guildManager.setSettingValue(GSettings.MUSIC_TOPIC, str);
enabled = "1".equals(str);
}
@@ -209,7 +210,7 @@ public class ConfigureCommand extends AbstractCommand {
String allowedPrefixes = "!$%?&*";
if (args.length == 1) {
String prefix = guildManager.getSetting(GuildManager.GSettings.PREFIX);
String prefix = guildManager.getSetting(GSettings.PREFIX);
context.reply("Current prefix for commands: '%s'", prefix);
context.reply("Allowed prefixes: %s", Arrays.toString(allowedPrefixes.toCharArray()));
@@ -220,7 +221,7 @@ public class ConfigureCommand extends AbstractCommand {
String prefix = args[1].trim();
if (prefix.length() == 1 && allowedPrefixes.contains(prefix)) {
guildManager.setSettingValue(GuildManager.GSettings.PREFIX, prefix);
guildManager.setSettingValue(GSettings.PREFIX, prefix);
context.reply("Prefix for commands is now '%s'", prefix);
} else {
@@ -15,7 +15,6 @@ import netneutrality.http.WebModule;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
@@ -15,7 +15,6 @@ import netneutrality.http.WebModule;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
@@ -15,7 +15,6 @@ import netneutrality.http.WebModule;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
@@ -15,7 +15,6 @@ import netneutrality.http.WebModule;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
@@ -0,0 +1,79 @@
package netneutrality.core;/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.music.MusicManager;
import netneutrality.music.TrackScheduler;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
public class BotState {
public static boolean SAFE = false;
//TODO: is it needed?
private static void saveGuildsState() {
Map<String, GuildManager> managers = GuildManager.getManagers();
JSONObject main = new JSONObject();
JSONArray guildsArray = new JSONArray();
for (GuildManager manager : managers.values()) {
MusicManager musicManager = MusicManager.get(manager.getGuild());
TrackScheduler trackScheduler = musicManager.getScheduler();
JSONObject guild = new JSONObject();
JSONObject music = new JSONObject();
guild.put("id", manager.getGuild().getId());
TextChannel currentChannel = trackScheduler.getTextChannel();
if (currentChannel == null) {
music.put("current_channel", "null");
} else {
music.put("current_channel", currentChannel.getId());
}
guild.put("music", music);
guildsArray.put(guild);
}
main.put("guilds", guildsArray);
File state = new File("state.json");
try {
if (!state.exists()) {
state.createNewFile();
}
try (FileWriter writer = new FileWriter(state)) {
writer.write(main.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void dump() {
if (!SAFE) {
saveGuildsState();
}
}
}
@@ -12,6 +12,7 @@ import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.NetNeutrality;
import netneutrality.db.DBController;
import netneutrality.db.GSettings;
import netneutrality.db.controllers.DBMessage;
import netneutrality.db.entities.OBlacklist;
import netneutrality.db.entities.OGuild;
@@ -21,7 +22,6 @@ import netneutrality.handler.ratelimiter.MessageRateLimiterImpl;
import netneutrality.thread.ThreadManager;
import netneutrality.utils.JpaUtils;
import netneutrality.utils.MessageFunction;
import netneutrality.utils.Settings;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
@@ -35,31 +35,6 @@ import java.util.concurrent.ConcurrentHashMap;
public class GuildManager {
public enum GSettings {
PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")),
MUSIC_ROLE("MUSIC_ROLE", ""),
MUSIC_CHANNEL("MUSIC_CHANNEL", ""),
MUSIC_VOLUME("MUSIC_VOLUME", "30"),
MUSIC_TOPIC("MUSIC_TOPIC", "0"),
BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", "");
private final String name;
private final String defaultValue;
GSettings(String name, String defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public String getDefaultValue() {
return defaultValue;
}
}
private static final Logger logger = LoggerFactory.getLogger(GuildManager.class);
private static final Map<String, GuildManager> managers = new ConcurrentHashMap<>();
private static final SessionFactory sessionFactory = SessionManager.getSessionFactory();
@@ -7,9 +7,11 @@ package netneutrality.core;
*/
import io.sentry.Sentry;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.core.context.CommandContext;
import netneutrality.exceptions.CommandErrorException;
import netneutrality.exceptions.CommandException;
import netneutrality.exceptions.CommandExecutionException;
import netneutrality.utils.MessageFunction;
import org.slf4j.Logger;
@@ -27,15 +29,19 @@ public class LogHandler {
public static void log(Exception e) {
if (e instanceof CommandErrorException) {
sendMessageToChannel((CommandErrorException) e);
} else if (e instanceof CommandExecutionException) {
logInternally((CommandErrorException) e);
return;
}
if (e instanceof CommandExecutionException) {
Sentry.captureException(e);
logInternally((CommandExecutionException) e);
tryLogToDebugChannel((CommandExecutionException) e);
} else {
Sentry.captureException(e);
logger.error(e.getMessage(), e);
return;
}
Sentry.captureException(e);
logger.error(e.getMessage(), e);
}
public static void log(String s, Exception e) {
@@ -47,12 +53,22 @@ public class LogHandler {
log((Exception) e);
}
private static void logInternally(CommandExecutionException error) {
public static void sendMessageToDebugChannel(Guild guild, String message) {
if (GuildManager.getManager(guild).isDebugEnabled()) {
guild.getTextChannels()
.stream()
.filter(textChannel -> textChannel.getName().equals("debug") || textChannel.getName().equals("log"))
.filter(TextChannel::canTalk)
.forEach(textChannel -> textChannel.sendMessage(message).queue());
}
}
private static void logInternally(CommandException error) {
CommandContext context = error.getCommandContext();
logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage(), error);
}
private static void tryLogToDebugChannel(CommandExecutionException error) {
private static void tryLogToDebugChannel(CommandException error) {
CommandContext context = error.getCommandContext();
if (context.getGuild() != null) {
@@ -65,12 +81,10 @@ public class LogHandler {
.forEach(textChannel -> textChannel.sendMessageEmbeds(MessageFunction.buildDebugMessage(context, error)).queue());
}
}
}
private static void sendMessageToChannel(CommandErrorException error) {
CommandContext context = error.getCommandContext();
logger.error("Exception thrown from command [{}] in guild [{}]: {}", context.getCommand().getCommandName(), context.getGuild().getId(), error.getMessage());
context.reply(error.getMessage());
}
}
@@ -47,7 +47,10 @@ public class SessionManager {
sessionFactory = metadata.getSessionFactoryBuilder().build();
} catch (Exception e) {
String env = Settings.getInstance().get("BOT_ENV", "dev");
if (!"dev".equals(env)) {
Sentry.captureException(e);
}
shutdown();
logger.error("Error connecting to database. Shutting down..", e);
@@ -1,67 +0,0 @@
package netneutrality.core;/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import netneutrality.music.MusicManager;
import netneutrality.music.TrackScheduler;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
public class UnsafeShutdown {
public static boolean SAFE = false;
//TODO: finish
private static void saveGuildsState() {
Map<String, GuildManager> managers = GuildManager.getManagers();
for (GuildManager manager : managers.values()) {
File state = new File("state.json");
try {
if (!state.exists()) {
state.createNewFile();
}
FileWriter writer = new FileWriter(state);
JSONArray array = new JSONArray();
MusicManager musicManager = MusicManager.get(manager.getGuild());
TrackScheduler trackScheduler = musicManager.getScheduler();
JSONObject music = new JSONObject();
music.put("current_channel", "");
music.put("current_topic", "");
music.put("current_topic", "");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void saveState() {
saveGuildsState();
}
}
@@ -156,6 +156,10 @@ public class CommandContext {
}
}
public void replyToMessage(String format, Object... arguments) {
replyToMessage(String.format(format, arguments));
}
public void replyToMessage(Message msg) {
if (channel != null && channel.canTalk() && message != null) {
message.reply(msg).queue();
@@ -0,0 +1,36 @@
package netneutrality.db;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import netneutrality.utils.Settings;
public enum GSettings {
//TODO: description
PREFIX("PREFIX", Settings.getInstance().get("BOT_PREFIX", "$")),
MUSIC_ROLE("MUSIC_ROLE", ""),
MUSIC_CHANNEL("MUSIC_CHANNEL", ""),
MUSIC_VOLUME("MUSIC_VOLUME", "30"),
MUSIC_TOPIC("MUSIC_TOPIC", "0"),
BLACKLIST_CHANNELS("BLACKLIST_EXCLUDE_CHANNELS", "");
private final String name;
private final String defaultValue;
GSettings(String name, String defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public String getDefaultValue() {
return defaultValue;
}
}
@@ -15,6 +15,7 @@ import netneutrality.command.AbstractCommand;
import netneutrality.core.CommandManager;
import netneutrality.core.GuildManager;
import netneutrality.core.context.CommandContext;
import netneutrality.db.GSettings;
import netneutrality.utils.Settings;
import org.jetbrains.annotations.NotNull;
@@ -39,7 +40,7 @@ public class MessageReceivedHandler extends ListenerAdapter {
String rawMessage = message.getContentDisplay().trim();
//String prefix = Settings.getInstance().get("BOT_PREFIX", "$");
String prefix = GuildManager.getManager(guild).getSetting(GuildManager.GSettings.PREFIX);
String prefix = GuildManager.getManager(guild).getSetting(GSettings.PREFIX);
if (rawMessage.startsWith(prefix)) {
rawMessage = rawMessage.replaceFirst(String.format("^[%s\\s]{1,}", prefix), "").trim();
@@ -1,10 +1,4 @@
package netneutrality.handler.hooks.voice;/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
package netneutrality.handler.hooks.voice;
/*
* Copyright (c) anthorob
*
@@ -1,10 +1,4 @@
package netneutrality.handler.ratelimiter;/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
package netneutrality.handler.ratelimiter;
/*
* Copyright (c) anthorob
*
@@ -18,6 +12,7 @@ import net.dv8tion.jda.api.entities.TextChannel;
import java.time.OffsetDateTime;
//TODO: to remove? or atleast make it useful
public class MessageRateLimiterImpl implements IMessageRateLimiter {
private final int messagePerSecond = 5;
private static Member lastSender;
@@ -1,5 +1,4 @@
package netneutrality.music;
/*
* Copyright (c) anthorob
*
@@ -7,33 +7,30 @@ package netneutrality.music;
* https://discord.gg/CdFcyQ
*/
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
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.source.AudioSourceManager;
import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager;
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager;
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.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.VoiceChannel;
import netneutrality.core.GuildManager;
import netneutrality.core.LogHandler;
import netneutrality.core.context.CommandContext;
import netneutrality.db.GSettings;
import netneutrality.exceptions.CommandExecutionException;
import netneutrality.music.loadable.LoadableSong;
import netneutrality.thread.MusicPlayerAutoDisconnectThread;
import netneutrality.thread.ThreadManager;
import netneutrality.utils.MessageFunction;
import netneutrality.utils.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -46,10 +43,11 @@ public class MusicManager {
private final static ScheduledExecutorService executor = (ScheduledExecutorService) ThreadManager.getExecutor("music", ThreadManager.ExecutorType.SCHEDULED);
private final static AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
private final static Map<String, AudioSourceManager> sources = new HashMap<>();
private final Guild guild;
private final AudioPlayer player;
private final TrackScheduler scheduler;
private TrackLoadingHandler lastLoadingHandler;
private TrackLoader lastTrackLoader;
private ScheduledFuture<?> autoDisconnectThread;
private final int baseVolume;
@@ -57,7 +55,7 @@ public class MusicManager {
this.guild = guild;
this.player = playerManager.createPlayer();
this.scheduler = new TrackScheduler(this);
this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GuildManager.GSettings.MUSIC_VOLUME));
this.baseVolume = Integer.parseInt(GuildManager.getManager(guild).getSetting(GSettings.MUSIC_VOLUME));
guild.getAudioManager().setSendingHandler(new AudioPlayerSendHandler(player));
player.addListener(scheduler);
@@ -74,21 +72,23 @@ public class MusicManager {
}
public static void initPlayerManager() {
AudioSourceManagers.registerRemoteSources(playerManager);
playerManager.registerSourceManager(new YoutubeAudioSourceManager(
true,
YoutubeAudioSourceManager youtubeSource = new YoutubeAudioSourceManager(true,
Settings.getInstance().get("GG_EMAIL", ""),
Settings.getInstance().get("GG_PASS", "")));
playerManager.registerSourceManager(SoundCloudAudioSourceManager.createDefault());
Settings.getInstance().get("GG_PASS", ""));
SoundCloudAudioSourceManager soundcloudSource = SoundCloudAudioSourceManager.createDefault();
sources.put("youtube", youtubeSource);
sources.put("soundcloud", soundcloudSource);
playerManager.registerSourceManager(youtubeSource);
playerManager.registerSourceManager(soundcloudSource);
}
public boolean isConnectedTo(VoiceChannel vChannel) {
return vChannel != null && vChannel.equals(guild.getAudioManager().getConnectedChannel());
public boolean isNotConnectedTo(VoiceChannel vChannel) {
return vChannel == null || !vChannel.equals(guild.getAudioManager().getConnectedChannel());
}
public synchronized void connect(VoiceChannel vChannel) {
if (vChannel != null && !isConnectedTo(vChannel)) {
if (vChannel != null && isNotConnectedTo(vChannel)) {
logger.debug("Guild {}: connecting to voice channel {}", vChannel.getGuild().getId(), vChannel.getId());
guild.getAudioManager().openAudioConnection(vChannel);
guild.getAudioManager().setSelfDeafened(true);
@@ -131,23 +131,21 @@ public class MusicManager {
return guild;
}
public TrackLoadingHandler getLastLoadingHandler() {
return lastLoadingHandler;
public void stopLoading() {
lastTrackLoader.stopLoading();
}
public synchronized void leave() {
if (isConnected()) {
if (guild != null && guild.getAudioManager().getConnectedChannel() != null) {
logger.debug("Guild {}: leaving voice channel {}", guild.getId(), guild.getAudioManager().getConnectedChannel().getId());
player.stopTrack();
guild.getAudioManager().closeAudioConnection();
}
scheduler.getTopicManager().detachTextChannel();
scheduler.detachTextChannel();
if (autoDisconnectThread != null) {
boolean cancel = autoDisconnectThread.cancel(true);
if (cancel)
autoDisconnectThread.cancel(true);
autoDisconnectThread = null;
}
}
@@ -167,41 +165,12 @@ public class MusicManager {
}
public synchronized void play(String url, CommandContext context, boolean needToBeConnected, boolean silent) {
Member member = context.getGuildUser();
TextChannel channel = context.getChannel();
logger.debug("Guild {}: request to play by user {}, string=[{}]", guild.getId(), context.getGuildUser().getId(), url);
logger.debug("Guild {}: request to play {} by user {}", guild.getId(), url, context.getGuildUser().getId());
if (member.getVoiceState() == null) {
context.deleteMessage();
return;
}
List<LoadableSong> toLoad = new ArrayList<>();
toLoad.add(new LoadableSong(null, url, null));
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) {
lastLoadingHandler = new TrackLoadingHandler(identifier, silent, this, context);
playerManager.loadItemOrdered(this, identifier, lastLoadingHandler);
} else {
context.replyToMessage("No source found to play the given url");
}
play(toLoad, context, needToBeConnected, silent);
}
public void play(List<LoadableSong> songs, CommandContext context, boolean needToBeConnected, boolean silent) {
@@ -209,103 +178,33 @@ public class MusicManager {
TextChannel channel = context.getChannel();
if (member.getVoiceState() == null) {
logger.error("Guild {}: Voice state is null", guild.getId());
context.replyToMessage("Voice state is null, something has gone wrong.");
LogHandler.log(new CommandExecutionException("Voice state is null", context, null));
return;
}
if (!member.getVoiceState().inVoiceChannel()) {
context.reply("You are not in a voice channel");
context.replyToMessage("You are not in a voice channel");
return;
}
VoiceChannel vChannel = member.getVoiceState().getChannel();
if (needToBeConnected && !isConnectedTo(vChannel)) {
context.reply("The player is not in your voice channel");
if (needToBeConnected && isNotConnectedTo(vChannel)) {
context.replyToMessage("The player is not in your voice channel");
return;
}
if (!isConnectedTo(vChannel)) {
if (isNotConnectedTo(vChannel)) {
connect(vChannel);
scheduler.attachTextChannel(channel);
}
scheduler.getTopicManager().attachTextChannel(channel);
boolean fromOnlineSource = songs.size() > 1;
for (LoadableSong song : songs) {
String identifier = SourceFinder.getIdentifier(song.name());
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();
scheduler.getQueueManager().queue(track, member);
if (!silent) {
//context.replyToMessage("Added track to queue");
context.reply(MessageFunction.buildAddingTrackMessage(track, member, identifier));
}
}
}
@Override
public void playlistLoaded(AudioPlaylist playlist) {
logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier);
if (!playlist.getTracks().isEmpty()) {
context.deleteMessage();
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");
}
}
TrackLoader loader = new TrackLoader(this, context, playerManager, silent);
lastTrackLoader = loader;
loader.loadAllSongs(songs);
}
public synchronized boolean removeFromQueue(int index) {
@@ -345,7 +244,13 @@ public class MusicManager {
// Minus the bot itself
int connected = voiceChannel.getMembers().size() - 1;
if (connected > 2) {
if (connected < 3) {
context.reply("Skipping current track since not enough people are connected to the voice channel.");
skip(1);
return;
}
double needed = connected / 2.1;
info.addSkip(context.getGuildUser());
@@ -357,18 +262,13 @@ public class MusicManager {
} else {
context.reply("Adding your vote to skip the current track. Current votes: %d/%d", info.getSkips().size(), (int) Math.ceil(needed));
}
} else {
context.reply("Skipping current track since not enough people are connected to the voice channel.");
skip(1);
}
}
public synchronized void setVolume(int volume) {
player.setVolume(volume);
}
public int getQueueSize () {
public int getQueueSize() {
synchronized (scheduler.getQueueManager().getQueue()) {
return scheduler.getQueueManager().getQueue().size();
}
@@ -117,7 +117,7 @@ public class QueueManager {
public void clearQueue() {
scheduler.getMusicManager().leave();
scheduler.getMusicManager().getLastLoadingHandler().stopLoading();
scheduler.getMusicManager().stopLoading();
synchronized (queue) {
queue.clear();
@@ -12,7 +12,7 @@ import java.util.regex.Pattern;
public class SourceFinder {
public enum AvailableSource {
public enum AudioSourceType {
Youtube,
Soundcloud,
Bandcamp,
@@ -24,23 +24,22 @@ public class SourceFinder {
private static final Pattern youtubePattern = Pattern.compile("^(?:https?://)?(?:(?:www\\.)?)?(?:youtube\\.com|youtu\\.be)/.*?(?:embed|e|v|watch.*?v=)?/?([-_a-z0-9]{10,})?(?:&?index=\\d+)?(?>(?:playlist\\?|&)?list=([^#\\\\&?]{12,}))?", Pattern.CASE_INSENSITIVE);
private static final Pattern soundcloudPattern = Pattern.compile("^(?:https?://)?(?:www\\.)?(?:m\\.)?soundcloud\\.com/([a-zA-Z0-9-_]+)/([a-zA-Z0-9-_]+)(?:\\\\?.*|)$", Pattern.CASE_INSENSITIVE);
private static Matcher BandcampMatcher;
private static Matcher vimeoMatcher;
private static Matcher twitchMatcher;
public static AvailableSource getSource(String url) {
public static AudioSourceType getSource(String url) {
Matcher youtubeMatcher = youtubePattern.matcher(url);
Matcher soundcloudMatcher = soundcloudPattern.matcher(url);
if (youtubeMatcher.find())
return AvailableSource.Youtube;
return AudioSourceType.Youtube;
if (soundcloudMatcher.find())
return AvailableSource.Soundcloud;
return AudioSourceType.Soundcloud;
if (!(url.startsWith("http://") || url.startsWith("https://")))
return AvailableSource.YTSearch;
return AudioSourceType.YTSearch;
return AvailableSource.Nothing;
return AudioSourceType.Nothing;
}
public static String getIdentifier(String url) {
@@ -1,84 +0,0 @@
package netneutrality.music;/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.core.GuildManager;
import org.apache.logging.log4j.LogManager;
import java.util.concurrent.TimeUnit;
public class TopicManager {
private final TrackScheduler scheduler;
private final Guild guild;
private TextChannel channel;
private String originalTopic;
public TopicManager(TrackScheduler scheduler) {
this.scheduler = scheduler;
this.guild = scheduler.getGuild();
}
public TrackScheduler getScheduler() {
return scheduler;
}
public Guild getGuild() {
return guild;
}
public TextChannel getTextChannel() {
return channel;
}
public String getOriginalTopic() {
return originalTopic;
}
public synchronized void attachTextChannel(TextChannel channel) {
this.channel = channel;
if (originalTopic == null) {
String current = channel.getTopic();
originalTopic = (current == null ? "" : current);
}
}
public synchronized void detachTextChannel() {
updateTopic(null);
this.channel = null;
this.originalTopic = null;
}
public synchronized void updateTopic(AudioTrack track) {
if (isEnabled() && channel != null) {
if (track == null) {
LogManager.getLogger(TopicManager.class).debug("Guild {}: Resetting topic for channel {}", guild.getId(), channel.getId());
channel.getManager().setTopic(originalTopic).queueAfter(5, TimeUnit.SECONDS);
} else {
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() {
// rate limiting too much
return false;
}
}
@@ -0,0 +1,116 @@
package netneutrality.music;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import netneutrality.core.LogHandler;
import netneutrality.core.context.CommandContext;
import netneutrality.music.loadable.CachedSource;
import netneutrality.music.loadable.LoadableMusicSource;
import netneutrality.music.loadable.LoadableSong;
import netneutrality.thread.ThreadManager;
import java.util.List;
public class TrackLoader implements Runnable {
private final CommandContext context;
private final MusicManager musicManager;
private final AudioPlayerManager audioPlayerManager;
private TrackLoadingHandler lastLoadingHandler;
private List<LoadableSong> songs;
private LoadableMusicSource source;
private int numberOfTracksLoaded;
private int totalNumberOfTracks;
private boolean loadingDisabled = false;
private boolean silent;
private final Object sync = new Object();
public TrackLoader(MusicManager musicManager, CommandContext context, AudioPlayerManager playerManager, boolean silent) {
this.musicManager = musicManager;
this.context = context;
this.audioPlayerManager = playerManager;
this.silent = silent;
}
public void loadAllSongs(List<LoadableSong> songs) {
this.songs = songs;
if (songs.size() > 1) {
silent = true;
}
ThreadManager.getExecutor("Track loader").submit(this);
}
public void loadAllSongs(CachedSource cachedSource) {
this.source = cachedSource.getSource();
loadAllSongs(cachedSource.getSongs());
}
public void stopLoading() {
loadingDisabled = true;
if (lastLoadingHandler != null) {
lastLoadingHandler.stopLoading();
}
}
@Override
public void run() {
for (LoadableSong song : songs) {
if (loadingDisabled) {
break;
}
SourceFinder.AudioSourceType type = SourceFinder.getSource(song.name());
String identifier = SourceFinder.getIdentifier(song.name());
if (identifier != null) {
TrackLoadingHandler loadingHandler = new TrackLoadingHandler(context, musicManager, identifier, type, silent);
loadingHandler.useCallbackOnLoad(success -> {
synchronized (sync) {
if (success) {
numberOfTracksLoaded++;
}
totalNumberOfTracks++;
System.out.println("notify, loaded: " + numberOfTracksLoaded + ", total: " + totalNumberOfTracks);
sync.notify();
}
});
lastLoadingHandler = loadingHandler;
audioPlayerManager.loadItemOrdered(this, identifier, loadingHandler);
} else {
if (songs.size() == 1) {
context.replyToMessage("No source found to play the given url");
}
}
}
try {
synchronized (sync) {
while (!(songs.size() == totalNumberOfTracks)) {
System.out.println("wait");
sync.wait();
}
//TODO: logic
if (songs.size() > 1 && source != null && !loadingDisabled) {
context.replyToMessage("Loaded %d of %d tracks from online source", numberOfTracksLoaded, totalNumberOfTracks);
}
}
} catch (InterruptedException exception) {
LogHandler.log(exception);
}
}
}
@@ -12,23 +12,29 @@ 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 netneutrality.core.LogHandler;
import netneutrality.core.context.CommandContext;
import netneutrality.utils.MessageFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Consumer;
public class TrackLoadingHandler implements AudioLoadResultHandler {
private final Logger logger = LoggerFactory.getLogger(TrackLoadingHandler.class);
private final String identifier;
private final SourceFinder.AudioSourceType type;
private final boolean silent;
private Consumer<Boolean> loadConsumer;
private boolean loadingDisabled = false;
private final Guild guild;
private final TrackScheduler scheduler;
private final CommandContext context;
public TrackLoadingHandler(String identifier, boolean silent, MusicManager manager, CommandContext context) {
public TrackLoadingHandler(CommandContext context, MusicManager manager, String identifier, SourceFinder.AudioSourceType type, boolean silent) {
this.identifier = identifier;
this.type = type;
this.silent = silent;
this.guild = manager.getGuild();
this.scheduler = manager.getScheduler();
@@ -40,45 +46,59 @@ public class TrackLoadingHandler implements AudioLoadResultHandler {
loadingDisabled = true;
}
public void useCallbackOnLoad(Consumer<Boolean> consumer) {
this.loadConsumer = consumer;
}
@Override
public void trackLoaded(AudioTrack audioTrack) {
if (loadConsumer != null) {
loadConsumer.accept(true);
}
if (loadingDisabled) {
return;
}
logger.debug("Guild {}: track loaded: {}", guild.getId(), identifier);
context.deleteMessage();
logger.debug("Guild {}: track loaded: {}", guild.getId(), audioTrack.getIdentifier());
scheduler.getQueueManager().queue(audioTrack, context.getGuildUser());
if (!silent) {
//context.replyToMessage("Added track to queue");
context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), identifier));
scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type));
// context.reply(MessageFunction.buildAddingTrackMessage(audioTrack, context.getGuildUser(), type));
}
}
@Override
public void playlistLoaded(AudioPlaylist audioPlaylist) {
if (loadConsumer != null) {
loadConsumer.accept(true);
}
if (loadingDisabled) {
return;
}
logger.debug("Guild {}: playlist loaded: {}", guild.getId(), identifier);
context.deleteMessage();
if (!audioPlaylist.getTracks().isEmpty()) {
if (audioPlaylist.isSearchResult()) {
AudioTrack track = audioPlaylist.getTracks().get(0);
scheduler.getQueueManager().queue(track, context.getGuildUser());
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, context.getGuildUser(), String.format("https://youtu.be/%s", track.getIdentifier())));
scheduler.sendMessageToChannel(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type));
// context.reply(MessageFunction.buildAddingTrackMessage(track, context.getGuildUser(), type));
}
} else {
return;
}
context.deleteMessage();
if (!silent) {
//context.replyToMessage("Added playlist to queue");
context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier));
scheduler.sendMessageToChannel(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type));
// context.reply(MessageFunction.buildAddingPlaylistMessage(audioPlaylist, context.getGuildUser(), identifier, type));
}
for (AudioTrack track : audioPlaylist.getTracks()) {
@@ -91,19 +111,28 @@ public class TrackLoadingHandler implements AudioLoadResultHandler {
}
}
}
}
@Override
public void noMatches() {
logger.debug("Guild {}: no matches for identifier {}", guild.getId(), identifier);
if (!silent)
context.replyToMessage("No matches found");
if (loadConsumer != null)
loadConsumer.accept(false);
}
@Override
public void loadFailed(FriendlyException e) {
logger.debug("Guild {}: load failed for identifier {}", guild.getId(), identifier, e);
LogHandler.log(e);
if (!silent)
context.replyToMessage("Failed to load track: " + e.getMessage());
if (loadConsumer != null)
loadConsumer.accept(false);
}
}
@@ -1,5 +1,4 @@
package netneutrality.music;
/*
* Copyright (c) anthorob
*
@@ -13,6 +12,9 @@ import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import netneutrality.core.LogHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,9 +22,9 @@ public class TrackScheduler extends AudioEventAdapter {
private final static Logger logger = LoggerFactory.getLogger(TrackScheduler.class);
private final QueueManager queueManager;
private final TopicManager topicManager;
private final MusicManager manager;
private final AudioPlayer player;
private TextChannel currentChannel;
private final Guild guild;
public TrackScheduler(MusicManager manager) {
@@ -30,17 +32,12 @@ public class TrackScheduler extends AudioEventAdapter {
this.player = manager.getPlayer();
this.guild = manager.getGuild();
this.queueManager = new QueueManager(this);
this.topicManager = new TopicManager(this);
}
public QueueManager getQueueManager() {
return queueManager;
}
public TopicManager getTopicManager() {
return topicManager;
}
public MusicManager getMusicManager() {
return manager;
}
@@ -53,6 +50,30 @@ public class TrackScheduler extends AudioEventAdapter {
return guild;
}
public TextChannel getTextChannel() {
return currentChannel;
}
public synchronized void attachTextChannel(TextChannel channel) {
this.currentChannel = channel;
}
public synchronized void detachTextChannel() {
this.currentChannel = null;
}
public void sendMessageToChannel(String msg) {
if (currentChannel != null && currentChannel.canTalk()) {
currentChannel.sendMessage(msg).queue();
}
}
public void sendMessageToChannel(MessageEmbed embed, MessageEmbed... embeds) {
if (currentChannel != null && currentChannel.canTalk()) {
currentChannel.sendMessageEmbeds(embed, embeds).queue();
}
}
@Override
public void onPlayerPause(AudioPlayer player) {
// Player was paused
@@ -66,7 +87,6 @@ public class TrackScheduler extends AudioEventAdapter {
@Override
public void onTrackStart(AudioPlayer player, AudioTrack track) {
logger.debug("Guild {}: starting track: {}", guild.getId(), track.getIdentifier());
topicManager.updateTopic(track);
}
@Override
@@ -84,7 +104,6 @@ public class TrackScheduler extends AudioEventAdapter {
if (endReason == AudioTrackEndReason.STOPPED) {
synchronized (queueManager.getQueue()) {
topicManager.updateTopic(null);
queueManager.getQueue().poll();
}
}
@@ -100,15 +119,14 @@ public class TrackScheduler extends AudioEventAdapter {
@Override
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.sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage());
LogHandler.log(exception);
sendMessageToChannel("Error while playing track [" + track.getInfo().title + "]: " + exception.getMessage());
}
@Override
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.sendMessageToChannel("Current track is stuck, skipping to next");
sendMessageToChannel("Current track is stuck, skipping to next");
queueManager.nextTrack(player);
}
}
@@ -15,7 +15,7 @@ public class CachedSource {
private OffsetDateTime lastAccess;
private final List<LoadableSong> songs;
public CachedSource(LoadableMusicSource source, List<LoadableSong> songs) {
protected CachedSource(LoadableMusicSource source, List<LoadableSong> songs) {
this.source = source;
this.lastAccess = OffsetDateTime.now();
this.songs = songs;
@@ -34,7 +34,8 @@ public class LoadableSourceManager {
}
return cachedSource;
} else {
}
List<LoadableSong> songs = loadFromUrl(source);
CachedSource newCachedSource = new CachedSource(source, songs);
@@ -42,8 +43,6 @@ public class LoadableSourceManager {
return newCachedSource;
}
}
private List<LoadableSong> loadFromUrl(LoadableMusicSource source) {
WebModule web = new WebModule(source.url());
JSONObject obj = web.request().getAsObject();
@@ -15,8 +15,11 @@ import net.dv8tion.jda.api.entities.*;
import netneutrality.command.AbstractCommand;
import netneutrality.command.CommandType;
import netneutrality.core.context.CommandContext;
import netneutrality.exceptions.CommandException;
import netneutrality.exceptions.CommandExecutionException;
import netneutrality.music.MusicManager;
import netneutrality.music.SourceFinder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DurationFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -69,40 +72,62 @@ public class MessageFunction {
return message.build();
}
public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member user, String identifier) {
public static MessageEmbed buildAddingTrackMessage(AudioTrack track, Member member, SourceFinder.AudioSourceType type) {
EmbedBuilder message = new EmbedBuilder();
message.setAuthor("Link to track", identifier);
message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier()));
String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl();
String url = track.getIdentifier();
String thumbnail = null;
if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) {
url = String.format("https://youtu.be/%s", track.getIdentifier());
thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", track.getIdentifier());
}
if (thumbnail != null) {
message.setThumbnail(thumbnail);
}
message.setTitle("Adding track to queue..");
message.setColor(Color.BLUE);
message.addField("Track title: ", track.getInfo().title, false);
message.addField("Track title: ", String.format("[**`%s`**](%s)", track.getInfo().title, url), 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 " + member.getEffectiveName(), avatarUrl);
message.setTimestamp(OffsetDateTime.now());
return message.build();
}
public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member user, String identifier) {
public static MessageEmbed buildAddingPlaylistMessage(AudioPlaylist playlist, Member member, String identifier, SourceFinder.AudioSourceType type) {
EmbedBuilder message = new EmbedBuilder();
message.setAuthor("Link to playlist", identifier);
message.setThumbnail(String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier()));
String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl();
String url = identifier;
String thumbnail = null;
if (type == SourceFinder.AudioSourceType.Youtube || type == SourceFinder.AudioSourceType.YTSearch) {
url = String.format("https://youtu.be/%s", playlist.getSelectedTrack().getIdentifier());
thumbnail = String.format("https://img.youtube.com/vi/%s/default.jpg", playlist.getSelectedTrack().getIdentifier());
}
if (thumbnail != null) {
message.setThumbnail(thumbnail);
}
message.setTitle("Adding playlist to queue..");
message.setColor(Color.BLUE);
message.addField("Playlist: ", playlist.getName(), false);
message.addField("Playlist: ", String.format("[**`%s`**](%s)", playlist.getName(), url), false);
message.addField("Number of tracks: ", String.valueOf(playlist.getTracks().size()), false);
message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl());
message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl);
message.setTimestamp(OffsetDateTime.now());
return message.build();
}
public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member user, boolean currentlyPlaying) {
public static MessageEmbed buildViewQueueMessage(MusicManager manager, Member member, boolean currentlyPlaying) {
String avatarUrl = StringUtils.isEmpty(member.getAvatarUrl()) ? member.getUser().getAvatarUrl() : member.getAvatarUrl();
ArrayList<AudioTrack> tracks = manager.getScheduler().getQueueManager().getAllQueuedTrack();
AudioTrack current = manager.getCurrentlyPlaying();
int numberofTracksShown = Math.min(tracks.size(), 10);
EmbedBuilder message = new EmbedBuilder();
message.setTitle("Current queue (showing 10 out of " + tracks.size() + " items):");
message.setTitle(String.format("Current queue (showing %d out of %d items):", numberofTracksShown, tracks.size()));
message.setColor(Color.BLUE);
int index = 0;
@@ -118,7 +143,7 @@ public class MessageFunction {
if (index == 10) break;
}
message.setFooter("Requested by " + user.getEffectiveName(), user.getAvatarUrl());
message.setFooter("Requested by " + member.getEffectiveName(), avatarUrl);
message.setTimestamp(OffsetDateTime.now());
return message.build();
@@ -191,7 +216,7 @@ public class MessageFunction {
return messages;
}
public static MessageEmbed buildDebugMessage(CommandContext context, CommandExecutionException error) {
public static MessageEmbed buildDebugMessage(CommandContext context, CommandException error) {
EmbedBuilder message = new EmbedBuilder();
message.setColor(Color.RED);
message.setTitle(":warning: Exception in command execution");
@@ -0,0 +1,26 @@
package netneutrality.utils;
/*
* Copyright (c) anthorob
*
* https://xtremcommunity.com/
* https://discord.gg/CdFcyQ
*/
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
public class MiscUtils {
public static boolean isValidUrl(String url) {
try {
URL object = new URL(url);
object.toURI();
return true;
} catch (MalformedURLException | URISyntaxException e) {
return false;
}
}
}