diff --git a/.gitignore b/.gitignore index acb08a7..e02c370 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +.idea + # User-specific stuff: .idea/**/workspace.xml .idea/**/tasks.xml diff --git a/pom.xml b/pom.xml index 28e7ebd..bb33a12 100644 --- a/pom.xml +++ b/pom.xml @@ -22,21 +22,28 @@ JDA LATEST - - mysql - mysql-connector-java - 5.1.38 - compile - com.fasterxml.jackson.dataformat jackson-dataformat-yaml - 2.3.0 + LATEST com.fasterxml.jackson.core jackson-databind - 2.2.3 + LATEST + compile + + + com.sedmelluq + lavaplayer + LATEST + compile + + + mysql + mysql-connector-java + 5.1.38 + compile org.apache.commons @@ -54,7 +61,6 @@ 4.3.9.RELEASE compile - ca.pjer chatter-bot-api @@ -96,7 +102,6 @@ - false @@ -112,17 +117,6 @@ - - maven-surefire-plugin - 2.19.1 - - false - false - - **/*.java - - - \ No newline at end of file diff --git a/src/main/java/io/rixa/bot/Rixa.java b/src/main/java/io/rixa/bot/Rixa.java index 0b6dd53..946d4e1 100644 --- a/src/main/java/io/rixa/bot/Rixa.java +++ b/src/main/java/io/rixa/bot/Rixa.java @@ -2,17 +2,22 @@ package io.rixa.bot; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import io.rixa.bot.commands.cmds.general.InfoCommand; -import io.rixa.bot.commands.cmds.general.PingCommand; -import io.rixa.bot.commands.cmds.general.ServerInfoCommand; +import io.rixa.bot.commands.cmds.admin.PMCommand; +import io.rixa.bot.commands.cmds.general.*; +import io.rixa.bot.commands.cmds.moderator.ClearCommand; +import io.rixa.bot.commands.cmds.moderator.MuteCommand; +import io.rixa.bot.commands.cmds.other.ShutdownCommand; import io.rixa.bot.commands.handler.CommandHandler; import io.rixa.bot.commands.perms.RixaPermission; -import io.rixa.bot.commands.cmds.general.HelpCommand; import io.rixa.bot.data.config.Configuration; import io.rixa.bot.data.storage.DatabaseAdapter; import io.rixa.bot.events.BotJoinListener; import io.rixa.bot.events.MessageListener; import io.rixa.bot.events.ReadyListener; +import io.rixa.bot.events.UserListener; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.guild.modules.module.MusicModule; import io.rixa.bot.utils.FileUtils; import lombok.Getter; import net.dv8tion.jda.core.AccountType; @@ -28,25 +33,33 @@ import javax.security.auth.login.LoginException; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.logging.Logger; public class Rixa { private static Rixa instance; - @Getter private CommandHandler commandHandler; - @Getter private Configuration configuration; - @Getter private ObjectMapper objectMapper; - @Getter private List shardList; - @Getter private File defaultPath; - @Getter private Logger logger; + @Getter + private CommandHandler commandHandler; + @Getter + private Configuration configuration; + @Getter + private ObjectMapper objectMapper; + @Getter + private List shardList; + @Getter + private File defaultPath; + @Getter + private Logger logger; private static long timeUp; private Rixa() { instance = this; logger = Logger.getLogger(Rixa.class.getCanonicalName()); objectMapper = new ObjectMapper(new YAMLFactory()); - defaultPath = new File("Rixa"); + defaultPath = new File("Rixa/"); commandHandler = new CommandHandler(); shardList = new ArrayList<>(); defaultPath.mkdirs(); @@ -55,41 +68,68 @@ public class Rixa { loadJDA(); } - public static long getTimeUp() { + public long getTimeUp() { return timeUp; } private void loadJDA() { + System.out.println("SHARDS: " + configuration.getShards()); // Remove this JDABuilder jda = new JDABuilder(AccountType.BOT) .setToken(configuration.getToken()) .setGame(Game.of(configuration.getBotGame())) .setEventManager(new AnnotatedEventManager()) - .addEventListener(new ReadyListener(), new BotJoinListener(), new MessageListener()) + .addEventListener(new ReadyListener(), new BotJoinListener(), new MessageListener(), + new UserListener()) .setAutoReconnect(true) .setAudioEnabled(true) .setEnableShutdownHook(false) .setStatus(OnlineStatus.ONLINE); for (int i = 0; i < configuration.getShards(); i++) { try { - getLogger().info("Loading Shard #" + (i + 1) + "!"); - getShardList().add(jda.useSharding(i, configuration.getShards()).buildBlocking()); - getLogger().info("Shard #" + (i + 1) + " has been loaded"); + getLogger().info("Loading Shard #" + (i + 1) + "!"); + getShardList().add(jda.useSharding(i, configuration.getShards()).buildBlocking()); + getLogger().info("Shard #" + (i + 1) + " has been loaded"); Thread.sleep(5000); } catch (InterruptedException | RateLimitedException | LoginException e) { e.printStackTrace(); } } - Runtime.getRuntime().addShutdownHook(new Thread(() -> getShardList().forEach(JDA::shutdown))); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + getShardList().forEach(JDA::shutdown); + getShardList().forEach(jdaInstance -> { + jdaInstance.getGuilds().forEach((Guild guild) -> { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + MusicModule musicModule = (MusicModule) rixaGuild.getModule("Music"); + musicModule.getMusicManager().getScheduler().getQueue().clear(); + musicModule.getMusicManager().getScheduler().getPlayer().destroy(); + guild.getAudioManager().setSendingHandler(null); + rixaGuild.save(); + }); + jdaInstance.shutdown(); + }); + })); timeUp = System.currentTimeMillis(); } private void registerCommands() { this.commandHandler.registerCommands( + new AdviceCommand("advice", RixaPermission.NONE, "Receive advice from the great beyond..."), + new ClearCommand("clear", RixaPermission.NONE, "Clear Chat!", Arrays.asList("deletemessages", "cmessages")), + new FeaturesCommand("features", RixaPermission.NONE, "List Rixa's official features!"), new HelpCommand("help", RixaPermission.NONE, "Review commands and its usages!"), new InfoCommand("info", RixaPermission.NONE, "Review information about a user or Rixa!"), + new MinecraftCommand("minecraft", RixaPermission.NONE, "See minecraft server info", Collections.singletonList("mc")), + new ModulesCommand("modules", RixaPermission.NONE, "List both enabled & disabled features of Rixa for this server!"), + new MusicCommand("music", RixaPermission.NONE, "Listen to music right from discord!"), + new MuteCommand("mute", RixaPermission.NONE, "Mute those pesky children!"), + new PingCommand("ping", RixaPermission.NONE, "Check Rixa's ping!"), + new PMCommand("pm", RixaPermission.NONE, "Private Message all users with a specific role!"), + new QuoteCommand("quote", RixaPermission.NONE, "Receive a quote from some of the greatest authors!"), + new RoleMemberList("listmembers", RixaPermission.NONE, "List all users with a specific role!"), new ServerInfoCommand("serverinfo", RixaPermission.NONE, "Review information about the server!"), - new PingCommand("ping", RixaPermission.NONE, "Check Rixa's ping!") - ); + new ShutdownCommand("shutdown", RixaPermission.NONE, "Shutdown Rixa!"), + new UrbanDictionaryCommand("ud", RixaPermission.NONE, "Look up urban definitions!"), + new YoutubeCommand("youtube", RixaPermission.NONE, "Search for music on youtube!")); } private void loadConfiguration() { @@ -113,7 +153,7 @@ public class Rixa { for (JDA jda : Rixa.getInstance().getShardList()) { System.out.println(jda.getShardInfo().toString()); System.out.println("JDA GUILDS:" + jda.getGuilds().size()); - if (jda == null || jda.getGuilds().size() == 0 || jda.getGuildById(id) == null) continue; + if (jda.getGuilds().size() == 0 || jda.getGuildById(id) == null) continue; guild = jda.getGuildById(id); break; } diff --git a/src/main/java/io/rixa/bot/apis/UrbanDictionary.java b/src/main/java/io/rixa/bot/apis/UrbanDictionary.java new file mode 100644 index 0000000..2249fc9 --- /dev/null +++ b/src/main/java/io/rixa/bot/apis/UrbanDictionary.java @@ -0,0 +1,48 @@ +package io.rixa.bot.apis; + +import lombok.Getter; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Scanner; + +public class UrbanDictionary { + + @Getter + private String wordToSearch; + @Getter + private String definition; + @Getter + private String permaLink; + public UrbanDictionary(String wordToSearch) { + this.wordToSearch = wordToSearch; + } + + public boolean search() throws IOException { + URL url = new URL("http://api.urbandictionary.com/v0/define?term=" + wordToSearch); + InputStream in = url.openStream(); + Scanner scan = new Scanner(in); + String jsonString = ""; + while(scan.hasNext()){ + jsonString += scan.next() + " "; + } + scan.close(); + in.close(); + try { + JSONObject obj = new JSONObject(jsonString.trim()); + JSONArray array = obj.getJSONArray("list"); + JSONObject newObj = array.getJSONObject(0); + this.wordToSearch = newObj.getString("word"); + this.permaLink = newObj.getString("permalink"); + this.definition = newObj.getString("definition"); + return true; + } catch(JSONException ex) { + return false; + } + } + +} diff --git a/src/main/java/io/rixa/bot/apis/YoutubeSearch.java b/src/main/java/io/rixa/bot/apis/YoutubeSearch.java new file mode 100644 index 0000000..bb0bb75 --- /dev/null +++ b/src/main/java/io/rixa/bot/apis/YoutubeSearch.java @@ -0,0 +1,103 @@ +package io.rixa.bot.apis; + +import io.rixa.bot.utils.WebUtil; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +public class YoutubeSearch { + + private static final String API_KEY; + private JSONArray items; + + static { + API_KEY = "AIzaSyD1wjRGbzKgvjqAU25pREy1dVio9WpcuS0"; + } + + public YoutubeSearch(String query) throws IOException { + try { + String url = "https://www.googleapis.com/youtube/v3/search?" + + "q=" + URLEncoder.encode(query, "UTF-8") + + "&part=id%2Csnippet&safeSearch=none&key=" + API_KEY; + search(url); + } catch (UnsupportedEncodingException ignored) { + } + } + + + public String getKind(int index) { + return items.getJSONObject(index).getString("kind"); + } + + public String getIdKind(int index) { + return items.getJSONObject(index).getJSONObject("id").getString("kind"); + } + + public String getVideoId(int index) { + if (!hasVideoId(index)) { + index++; + } + return items.getJSONObject(index).getJSONObject("id").getString("videoId"); + } + + public boolean hasVideoId(int index) { + return items.getJSONObject(index).getJSONObject("id").has("videoID"); + } + + public String getPublishedTime(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("publishedAt"); + } + + public String getChannelId(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("channelId"); + } + + public String getTitle(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("title"); + } + + public String getDescription(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("description"); + } + + public String getChannelTitle(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("channelTitle"); + } + + public String getLiveBroadcastContent(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getString("liveBroadcastContent"); + } + + public String getThumbnailDefaultUrl(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getJSONObject("default").getString("url"); + } + + public String getThumbnailMediumUrl(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getJSONObject("medium").getString("url"); + } + + public String getThumbnailHighUrl(int index) { + return items.getJSONObject(index).getJSONObject("snippet").getJSONObject("high").getString("url"); + } + + public String getUrl(int index) { + String YOUTUBE_WATCH_BASE_URL = "https://www.youtube.com/watch?v="; + return YOUTUBE_WATCH_BASE_URL + getVideoId(index); + } + + private void search(String url) throws IOException { + String json = WebUtil.getWebPage(url); + + JSONObject obj = new JSONObject(json); + try { + items = obj.getJSONArray("items"); + } catch (JSONException e) { + System.out.println("No search results found.");// throw new NotFoundException("No results found."); + } + } + +} \ No newline at end of file diff --git a/src/main/java/io/rixa/bot/commands/Command.java b/src/main/java/io/rixa/bot/commands/Command.java index 3077b70..9b67a85 100644 --- a/src/main/java/io/rixa/bot/commands/Command.java +++ b/src/main/java/io/rixa/bot/commands/Command.java @@ -3,8 +3,12 @@ package io.rixa.bot.commands; import io.rixa.bot.commands.perms.RixaPermission; import lombok.Getter; import lombok.Setter; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import java.io.IOException; import java.util.Collections; import java.util.List; @@ -32,5 +36,7 @@ public abstract class Command { setAliases(aliases); } - public abstract void execute(GuildMessageReceivedEvent event); + // public abstract void execute(GuildMessageReceivedEvent event); + + public abstract void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) throws IOException; } diff --git a/src/main/java/io/rixa/bot/commands/cmds/admin/PMCommand.java b/src/main/java/io/rixa/bot/commands/cmds/admin/PMCommand.java new file mode 100644 index 0000000..aa074a7 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/admin/PMCommand.java @@ -0,0 +1,48 @@ +package io.rixa.bot.commands.cmds.admin; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.DiscordUtils; +import io.rixa.bot.utils.MessageFactory; +import lombok.Getter; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Role; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.exceptions.ErrorResponseException; +import net.dv8tion.jda.core.requests.ErrorResponse; + +public class PMCommand extends Command { + + @Getter private RixaPermission rixaPermission; + public PMCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + this.rixaPermission = rixaPermission; + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + String msg = String.join(" ", args); + Role role = DiscordUtils.getMentionedRole(guild, msg); + if (role == null) { + MessageFactory.create(String.format + ("You must mention a role to private message! Example: `%s @role this is a test private message!`", + commandLabel)).queue(channel); + return; + } + msg = msg.replaceFirst(role.getAsMention(), "").replaceFirst("@" + role.getName(),""); + int usersWithRole = 0; + int sendingFailed = 0; + for (Member memberWithRole : guild.getMembersWithRoles(role)) { + try { + memberWithRole.getUser().openPrivateChannel().complete().sendMessage(msg).queue(); + usersWithRole++; + } catch (ErrorResponseException ex) { + if (ex.getErrorResponse() == ErrorResponse.CANNOT_SEND_TO_USER) + sendingFailed++; + } + } + MessageFactory.create("```" + msg + "```") + .footer("Successful Deliveries: " + usersWithRole + " | Failed Deliveries: " + sendingFailed, guild.getIconUrl()).queue(channel); + } +} \ No newline at end of file diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/AdviceCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/AdviceCommand.java new file mode 100644 index 0000000..a45a8f8 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/AdviceCommand.java @@ -0,0 +1,39 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import io.rixa.bot.utils.WebUtil; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import org.json.JSONObject; + +import java.io.IOException; + +public class AdviceCommand extends Command { + + public AdviceCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + MessageFactory.create(getAdvice()).setTitle("Advice Request").footer("Requested by: " + member.getEffectiveName(), member.getUser().getEffectiveAvatarUrl()) + .setColor(member.getColor()).queue(channel); + } + + private String getAdvice() { + String json; + try { + json = WebUtil.getWebPage("http://api.adviceslip.com/advice"); + } catch (IOException e) { + return "Could not find any advice for you."; + } + + JSONObject obj = new JSONObject(json); + JSONObject slip = obj.getJSONObject("slip"); + return slip.getString("advice"); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/FeaturesCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/FeaturesCommand.java new file mode 100644 index 0000000..4296ddb --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/FeaturesCommand.java @@ -0,0 +1,30 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; + +public class FeaturesCommand extends Command { + + private String[] features = { + "Music", "Economy", "Moderation", "Server List", "User Profiles", + "Role Management", "Fun Commands", "Custom Commands", "Games", "& more." + }; + + public FeaturesCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + MessageFactory.create((features == null || features.length == 0) ? "There are currently no features listed." : + "Rixa Features: " + String.join("\n", features + )).setColor(member.getColor()).queue(channel); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/HelpCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/HelpCommand.java index 73d0e8d..c5edbae 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/general/HelpCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/general/HelpCommand.java @@ -4,7 +4,10 @@ import io.rixa.bot.commands.Command; import io.rixa.bot.commands.perms.RixaPermission; import io.rixa.bot.utils.MessageFactory; import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.core.exceptions.ErrorResponseException; import net.dv8tion.jda.core.exceptions.PermissionException; @@ -16,24 +19,21 @@ public class HelpCommand extends Command { } @Override - public void execute(GuildMessageReceivedEvent event) { - try { - event.getMessage().delete().complete(); - } catch (PermissionException ignored) {} + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { EmbedBuilder embedBuilder = new EmbedBuilder(); String stringBuilder = "\u2753" + " **Help**" + "\n" + "Click the corresponding number for more information about the command menu."; - embedBuilder.setTitle(String.format("Help: %s", event.getGuild().getId())) + embedBuilder.setTitle(String.format("Help: %s", guild.getId())) .setDescription(stringBuilder) .addField("1 - General Commands", "Reveals usable commands intended for `everyone`", false) .addField("2 - Staff Commands", "Reveals usable commands intended for `staff` use only", false) .addField("3 - Music Commands", "Reveals usable commands to configure Rixa for your discord!", false) - .setColor(event.getMember().getColor()); - Message message = event.getAuthor().openPrivateChannel().complete().sendMessage(embedBuilder.build()).complete(); - MessageFactory.create(event.getMember().getAsMention() - + ", the help menu has been private messaged to you!").setColor(event.getMember().getColor()).queue(event.getChannel()); + .setColor(member.getColor()); + Message message = member.getUser().openPrivateChannel().complete().sendMessage(embedBuilder.build()).complete(); + MessageFactory.create(member.getAsMention() + + ", the help menu has been private messaged to you!").setColor(member.getColor()).queue(channel); try { message.addReaction("\u0031\u20E3").queue(); message.addReaction("\u0032\u20E3").queue(); diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/InfoCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/InfoCommand.java index aab5a2e..0cd5ba0 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/general/InfoCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/general/InfoCommand.java @@ -8,15 +8,14 @@ import io.rixa.bot.utils.MessageFactory; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDAInfo; -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.entities.MessageEmbed; -import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.concurrent.TimeUnit; public class InfoCommand extends Command { @@ -26,33 +25,32 @@ public class InfoCommand extends Command { } @Override - public void execute(GuildMessageReceivedEvent event) { - System.out.println("INFO COMMAND TRIGGERED"); - String[] messages = event.getMessage().getContent().split(" "); - System.out.println(messages.length); - if(messages.length >= 2) { - Member member = DiscordUtils.memberSearch(event.getGuild(), event.getMessage().getContent(), false).get(0); + public void execute(String commandLabel, Guild guild, Member author, TextChannel channel, String[] args) { + if(args.length >= 1) { + Member member = DiscordUtils.memberSearch(guild, String.join(" ", args), false).get(0); User user = member.getUser(); OffsetDateTime time = user.getCreationTime(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM/dd/yyyy HH:mm:ss"); + List roles = new ArrayList<>(); + member.getRoles().forEach(role -> roles.add(role.getName())); MessageFactory.create("Playing **" + (member.getGame() == null ? "Unknown" : member.getGame().getName()) + "**") .setColor(member.getColor()) .setThumbnail(user.getAvatarUrl()) .setAuthor("User Information: " + user.getName(), null, user.getAvatarUrl()) .addField("User", user.getAsMention(), true) .addField("ID", user.getId(), true) - .addField("Roles", String.valueOf(member.getRoles().size()), true) + .addField("Roles: "+ member.getRoles().size(), String.join(" **,** " + roles), true) .addField("Status", member.getOnlineStatus().name(), true) .addField("Mutual Guilds", String.valueOf(user.getMutualGuilds().size()), true) .addField("Nickname", member.getNickname() == null ? "None" : member.getNickname(), true) .addField("Created", time.format(formatter), true) .addField("Joined", member.getJoinDate().format(formatter), true) - .queue(event.getChannel()); + .queue(channel); return; } - User botOwner = event.getJDA().getUserById("202944101333729280"); + User botOwner = guild.getJDA().getUserById("202944101333729280"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"); - Date date1 = new Date(Rixa.getTimeUp()); + Date date1 = new Date(Rixa.getInstance().getTimeUp()); long difference = new Date().getTime() - date1.getTime(); long seconds = difference / 1000; int day = (int) TimeUnit.SECONDS.toDays(seconds); @@ -71,13 +69,14 @@ public class InfoCommand extends Command { "levels, and more. Rixa was created to bring ease and simplicity to managing Discord servers, and has since grown into much more than just a bot used for " + "moderation.") .setTitle("Rixa Discord Bot", "http://rixa.io/") - .addField("Created", event.getJDA().getSelfUser().getCreationTime().format(formatter), true) + .addField("Created", guild.getJDA().getSelfUser().getCreationTime().format(formatter), true) .addField("Bot Uptime ", uptime, true) .addField("Total Guilds", String.valueOf(guildCount), true) .addField("Total Users", String.valueOf(userCount), true) .addField("JDA Version", JDAInfo.VERSION, true) .addField("Rixa Developer", botOwner.getName() + "#" + botOwner.getDiscriminator(), true) - .footer("Requested by " + event.getAuthor().getName() + "#" + event.getAuthor().getDiscriminator(), event.getAuthor().getAvatarUrl()) - .queue(event.getChannel()); + .footer("Requested by " + author.getUser().getName() + "#" + author.getUser().getDiscriminator(), author.getUser().getAvatarUrl()) + .queue(channel); } + } diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/MinecraftCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/MinecraftCommand.java new file mode 100644 index 0000000..711cd7a --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/MinecraftCommand.java @@ -0,0 +1,60 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import io.rixa.bot.utils.WebUtil; +import net.dv8tion.jda.core.entities.Channel; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.List; + +public class MinecraftCommand extends Command { + + public MinecraftCommand(String command, RixaPermission rixaPermission, String description, Listaliases) { + super(command, rixaPermission, description, aliases); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + if (args.length == 0) { + MessageFactory.create("Incorrect Usage! Try " + args[0] + " {IP}:{PORT}").setColor(member.getColor()).queue(channel); + return; + } + + String ipAddress = args[1]; + + JSONObject object = get(ipAddress); + if (object == null || !object.getBoolean("status")) { + // Not correct + MessageFactory.create("Server Information not found!").setColor(member.getColor()).queue(channel); + return; + } + JSONObject onlineObject = object.getJSONObject("players"); + MessageFactory.create( + object.getJSONObject("motds").getString("clean")) + .setTitle(ipAddress) + .addField("Version", object.getString("version"), true) + .addField("Online Players", (onlineObject == null) ? "0/0" : onlineObject.getInt("online") + "/" + onlineObject.getInt("max"), true) + .addField("Ping", String.valueOf(object.getInt("ping")), true) + .setImage(String.format("https://use.gameapis.net/mc/query/banner/%s/night,caps", ipAddress)) + .addThumbnail("https://use.gameapis.net/mc/query/icon/" + ipAddress) + .queue(channel); + } + + private JSONObject get(String ip) { + String json; + try { + json = WebUtil.getWebPage("https://use.gameapis.net/mc/query/info/" + ip); + } catch (IOException e) { + return null; + } + return new JSONObject(json); + } + +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/ModulesCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/ModulesCommand.java new file mode 100644 index 0000000..7a0f2ff --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/ModulesCommand.java @@ -0,0 +1,32 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; + +import java.util.ArrayList; +import java.util.List; + +public class ModulesCommand extends Command { + + public ModulesCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + List modules = new ArrayList<>(); + rixaGuild.getModules().values().forEach + (module -> modules.add(String.format("%s [%s]", module.getName(), (module.isEnabled()) ? "Enabled" : "Disabled"))); + String moduleMessage = String.format( + "Modules: \n%s", + String.join(",\n", modules)); + MessageFactory.create(moduleMessage).setColor(member.getColor()).setThumbnail(guild.getIconId()).queue(channel); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/MusicCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/MusicCommand.java new file mode 100644 index 0000000..1eacdca --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/MusicCommand.java @@ -0,0 +1,344 @@ +package io.rixa.bot.commands.cmds.general; + +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.bandcamp.BandcampAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.beam.BeamAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager; +import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; +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 io.rixa.bot.apis.YoutubeSearch; +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.guild.modules.module.MusicModule; +import io.rixa.bot.guild.modules.module.music.MusicManager; +import io.rixa.bot.pagination.QueuePagination; +import io.rixa.bot.utils.DiscordUtils; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.MessageBuilder; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.entities.VoiceChannel; +import net.dv8tion.jda.core.exceptions.PermissionException; +import org.apache.commons.lang3.StringUtils; + +import java.awt.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class MusicCommand extends Command { + + private final int DEFAULT_VOLUME = 35; + private final AudioPlayerManager playerManager; + + public MusicCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + this.playerManager = new DefaultAudioPlayerManager(); + this.playerManager.registerSourceManager(new YoutubeAudioSourceManager()); + this.playerManager.registerSourceManager(new SoundCloudAudioSourceManager()); + this.playerManager.registerSourceManager(new BandcampAudioSourceManager()); + this.playerManager.registerSourceManager(new VimeoAudioSourceManager()); + this.playerManager.registerSourceManager(new TwitchStreamAudioSourceManager()); + this.playerManager.registerSourceManager(new HttpAudioSourceManager()); + this.playerManager.registerSourceManager(new LocalAudioSourceManager()); + this.playerManager.registerSourceManager(new BeamAudioSourceManager()); + + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + MusicManager musicManager = getMusicManager(rixaGuild); + AudioPlayer player = musicManager.getPlayer(); + QueuePagination queuePagination = musicManager.getScheduler().getQueuePagination(); + if (args.length == 1) { + switch (args[0].toLowerCase()) { + case "leave": + MessageFactory.create("Leaving voice channel...").setColor(member.getColor()).queue(channel); + reset(guild, musicManager); + channel.getGuild().getAudioManager().closeAudioConnection(); + break; + case "join": + case "summon": + if (member.getVoiceState().getChannel() == null) { + MessageFactory.create("You must be in a voice channel to summon me!").setColor(member.getColor()).queue(channel); + return; + } + VoiceChannel voiceChannel = member.getVoiceState().getChannel(); + joinVoice(voiceChannel, member, channel); + break; + case "pause": + case "resume": + case "play": + if (player.isPaused()) { + player.setPaused(false); + MessageFactory.create("MusicPlayer resumed track: " + player.getPlayingTrack().getInfo().title).setColor(member.getColor()).queue(channel); + } else if (!(player.isPaused())) { + player.setPaused(false); + MessageFactory.create("MusicPlayer paused track: " + player.getPlayingTrack().getInfo().title).setColor(member.getColor()).queue(channel); + } else if (player.getPlayingTrack() != null) { + MessageFactory.create("MusicPlayer already playing track: " + player.getPlayingTrack().getInfo().title).setColor(member.getColor()).queue(channel); + } else if (musicManager.getScheduler().getQueue().isEmpty()) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + } + break; + case "stop": + musicManager.getScheduler().getQueue().clear(); + player.stopTrack(); + player.setPaused(false); + MessageFactory.create("The music player has been stopped and queue has been cleared.").setColor(member.getColor()).queue(channel); + break; + case "skip": + AudioTrack audioTrack = musicManager.getScheduler().nextTrack(); + if (audioTrack == null) { + MessageFactory.create("The queue is now empty, add more to continue to listen to music!").setColor(member.getColor()).queue(channel); + return; + } + MessageFactory.create("Successfully skipped current track. Now playing: " + audioTrack.getInfo().title).setColor(member.getColor()).queue(channel); + break; + case "nowplaying": + case "np": + audioTrack = musicManager.getScheduler().getPlayer().getPlayingTrack(); + if (audioTrack == null) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + return; + } + MessageFactory.create().setAuthor(audioTrack.getInfo().title, "https://i.imgur.com/lOoybhD.png") + .addField("Author", audioTrack.getInfo().author, true) + .addField("Duration", getTimestamp(audioTrack.getInfo().length), true) + .addField("Position", getTimestamp(audioTrack.getPosition()), true).queue(channel); + break; + case "playlist": + case "queue": + case "list": + if (musicManager.getScheduler().getQueue().size() == 0) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + return; + } + List firstPage = queuePagination.getPage(1); + if (firstPage == null || firstPage.isEmpty()) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + return; + } + List titles = new ArrayList<>(); + for (int i = 0; i < firstPage.size(); i++) { + if (firstPage.get(i) == null) continue; + titles.add("`" + (i + 1) + ")` " + firstPage.get(i).getInfo().title); + } + MessageFactory.create(String.join("\n", titles)).setAuthor("Music Queue", "https://i.imgur.com/lOoybhD.png").queue(channel); + break; + case "restart": + audioTrack = player.getPlayingTrack(); + if (audioTrack == null) { + audioTrack = musicManager.getScheduler().getLastTrack(); + } + if (audioTrack == null) { + MessageFactory.create("No track has been previously played.").setColor(member.getColor()).queue(channel); + return; + } + MessageFactory.create("Restarting Track: " + audioTrack.getInfo().title).setColor(member.getColor()).queue(channel); + player.playTrack(audioTrack.makeClone()); + break; + case "repeat": + musicManager.getScheduler().setRepeating(!musicManager.getScheduler().isRepeating()); + MessageFactory.create("Music repeat has been " + (musicManager.getScheduler().isRepeating() ? "enabled" : "disabled")) + .setColor(member.getColor()).queue(channel); + break; + case "playlistrepeat": + case "pr": + musicManager.getScheduler().setPlaylistRepeat(!musicManager.getScheduler().isPlaylistRepeat()); + MessageFactory.create("Playlist repeat has been " + (musicManager.getScheduler().isPlaylistRepeat() ? "enabled" : "disabled")) + .setColor(member.getColor()).queue(channel); + break; + case "reset": + reset(guild, musicManager); + guild.getAudioManager().setSendingHandler(musicManager.getSendHandler()); + MessageFactory.create("The player has been completely reset!").setColor(member.getColor()).queue(channel); + break; + case "shuffle": + if (musicManager.getScheduler().getQueue().isEmpty()) { + MessageFactory.create("The queue is currently empty!").setColor(member.getColor()).queue(channel); + return; + } + musicManager.getScheduler().shuffle(); + MessageFactory.create("The queue has been shuffled!").setColor(member.getColor()).queue(channel); + break; + } + } else if (args.length == 2) { + String string = StringUtils.join(args, " ", 1, args.length); + switch (args[0].toLowerCase()) { + case "join": + VoiceChannel voiceChannel = DiscordUtils.voiceChannelSearch(guild, string); + if (voiceChannel == null) { + return; + } + joinVoice(voiceChannel, member, channel); + break; + case "play": + case "playlist": + case "pplay": + if (member.getVoiceState().getChannel() == null) { + MessageFactory.create("You must be in a voice channel to summon me!").setColor(member.getColor()).queue(channel); + return; + } + if (guild.getSelfMember().getVoiceState().getChannel() == null) { + joinVoice(member.getVoiceState().getChannel(), member, channel); + } + loadAndPlay(musicManager, channel, args[1], (args[1].toLowerCase().contains("playlist") + || args[0].equalsIgnoreCase("playlist") + || args[0].equalsIgnoreCase("pplay"))); + break; + case "volume": + case "vol": + try { + int newVolume = Math.max(10, Math.min(100, Integer.parseInt(args[1]))); + int oldVolume = player.getVolume(); + player.setVolume(newVolume); + MessageFactory.create("Music player volume updated from `" + oldVolume + "` to `" + newVolume + "`").setColor(member.getColor()).queue(channel); + } catch (NumberFormatException e) { + MessageFactory.create(args[1] + " is not a valid integer. Try a number between 10 and 100.").setColor(member.getColor()).queue(channel); + } + break; + case "forward": + if (player.getPlayingTrack() == null) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + return; + } + try { + player.getPlayingTrack().setPosition(Math.max(0, player.getPlayingTrack().getPosition() + (Integer.parseInt(args[1]) * 1000))); + } catch (NumberFormatException e) { + MessageFactory.create(args[1] + " is not a valid integer. Try `10`!").setColor(member.getColor()).queue(channel); + } + break; + case "back": + if (player.getPlayingTrack() == null) { + MessageFactory.create("The audio queue is empty! Add a track to the queue first!").setColor(member.getColor()).queue(channel); + return; + } + try { + player.getPlayingTrack().setPosition(Math.max(0, player.getPlayingTrack().getPosition() - (Integer.parseInt(args[1]) * 1000))); + } catch (NumberFormatException e) { + MessageFactory.create(args[1] + " is not a valid integer. Try `10`!").setColor(member.getColor()).queue(channel); + } + break; + } + } else if (args.length >= 3) { + String string = StringUtils.join(args, " ", 1, args.length); + switch (args[0].toLowerCase()) { + case "join": + VoiceChannel voiceChannel = DiscordUtils.voiceChannelSearch(guild, string); + if (voiceChannel == null) { + MessageFactory.create("Sorry I was unable to find the VoiceChannel: `" + string + "`.").setColor(member.getColor()).queue(channel); + } + joinVoice(voiceChannel, member, channel); + break; + case "youtube": + case "ytsearch": + case "yt": + case "search": + try { + YoutubeSearch ytSearch = new YoutubeSearch(string); + loadAndPlay(musicManager, channel, ytSearch.getUrl(0), false); + } catch (IOException e) { + MessageFactory.create("Error Occurred: Could not play youtube video.").setColor(member.getColor()).queue(channel); + } + break; + } + } + } + + private void joinVoice(VoiceChannel voiceChannel, Member member, TextChannel channel) { + try { + channel.getGuild().getAudioManager().openAudioConnection(voiceChannel); + MessageFactory.create("Entering Voice Channel: " + voiceChannel.getName()).setColor(member.getColor()).queue(channel); + } catch (PermissionException e) { + if (e.getPermission() == Permission.VOICE_CONNECT) { + MessageFactory.create("I do not have permission to join the requested voice channel.").setColor(member.getColor()).queue(channel); + } + } + } + + private void reset(Guild guild, MusicManager musicManager) { + synchronized (musicManager) { + musicManager.getScheduler().getQueue().clear(); + musicManager.getScheduler().getPlayer().destroy(); + guild.getAudioManager().setSendingHandler(null); + } + } + + private void loadAndPlay(MusicManager mng, final TextChannel channel, final String trackUrl, final boolean addPlaylist) { + playerManager.loadItemOrdered(mng, trackUrl, new AudioLoadResultHandler() { + @Override + public void trackLoaded(AudioTrack track) { + String msg = "Adding to queue: " + track.getInfo().title; + mng.getScheduler().queue(track); + MessageFactory.create(msg).setColor(Color.decode("#4CC276")).queue(channel); + } + + @Override + public void playlistLoaded(AudioPlaylist playlist) { + AudioTrack firstTrack = playlist.getSelectedTrack(); + List tracks = playlist.getTracks(); + + if (firstTrack == null) { + firstTrack = playlist.getTracks().get(0); + } + + if (addPlaylist) { + MessageFactory.create("Adding (" + playlist.getTracks().size() + ") tracks to queue from playlist: " + playlist.getName()).setColor(Color.decode("#4CC276")).queue(channel); + tracks.forEach(mng.getScheduler()::queue); + } else { + MessageFactory.create("Adding to queue " + firstTrack.getInfo().title + " (first track of playlist " + playlist.getName() + ")").setColor(Color.decode("#4CC276")).queue(channel); + mng.getScheduler().queue(firstTrack); + } + } + + @Override + public void noMatches() { + MessageFactory.create("Nothing found by " + trackUrl).setColor(Color.decode("#4CC276")).queue(channel); + } + + @Override + public void loadFailed(FriendlyException exception) { + MessageFactory.create("Could not play: " + exception.getMessage()).setColor(Color.decode("#4CC276")).queue(channel); + exception.printStackTrace(); + } + }); + } + + public MusicManager getMusicManager(RixaGuild guild) { + MusicModule musicModule = (MusicModule) guild.getModule("Music"); + if (musicModule.getMusicManager() != null) { + return musicModule.getMusicManager(); + } + MusicManager musicManager = new MusicManager(this.playerManager); + musicManager.getPlayer().setVolume(DEFAULT_VOLUME); + musicModule.setMusicManager(musicManager); + return musicManager; + } + + private String getTimestamp(long milliseconds) { + int seconds = (int) (milliseconds / 1000) % 60; + int minutes = (int) ((milliseconds / (1000 * 60)) % 60); + int hours = (int) ((milliseconds / (1000 * 60 * 60)) % 24); + + if (hours > 0) + return String.format("%02d:%02d:%02d", hours, minutes, seconds); + else + return String.format("%02d:%02d", minutes, seconds); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/PingCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/PingCommand.java index 1af1d6f..ed896b9 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/general/PingCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/general/PingCommand.java @@ -3,6 +3,9 @@ package io.rixa.bot.commands.cmds.general; import io.rixa.bot.commands.Command; import io.rixa.bot.commands.perms.RixaPermission; import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; public class PingCommand extends Command { @@ -12,7 +15,7 @@ public class PingCommand extends Command { } @Override - public void execute(GuildMessageReceivedEvent event) { - MessageFactory.create("Pong! [" + event.getJDA().getPing() + "ms]").setColor(event.getMember().getColor()).queue(event.getChannel()); + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + MessageFactory.create("Pong! [" + guild.getJDA().getPing() + "ms]").setColor(member.getColor()).queue(channel); } } diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/QuoteCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/QuoteCommand.java new file mode 100644 index 0000000..709e804 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/QuoteCommand.java @@ -0,0 +1,50 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import io.rixa.bot.utils.WebUtil; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import org.json.JSONObject; + +import java.io.IOException; + +public class QuoteCommand extends Command { + + public QuoteCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + + } + + public void execute(GuildMessageReceivedEvent event) { + String[] quote = getAdvice(); + MessageFactory.create(quote[0]).setTitle("Author: " + quote[1]).footer("Requested by: " + event.getMember().getEffectiveName(), event.getAuthor().getEffectiveAvatarUrl()) + .setColor(event.getMember().getColor()).queue(event.getChannel()); + } + + private String[] getAdvice() { + String[] strings = new String[2]; + String json; + try { + json = WebUtil.getWebPage("https://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=json"); + } catch (IOException e) { + strings[0] = "Could not find any quotes for you."; + strings[1] = "Author not found"; + return strings; + } + + JSONObject obj = new JSONObject(json); + String quote = obj.getString("quoteText"); + String author = obj.getString("quoteAuthor"); + strings[0] = quote; + strings[1] = author; + return strings; + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/RoleMemberList.java b/src/main/java/io/rixa/bot/commands/cmds/general/RoleMemberList.java new file mode 100644 index 0000000..45e22fc --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/RoleMemberList.java @@ -0,0 +1,48 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.DiscordUtils; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Role; +import net.dv8tion.jda.core.entities.TextChannel; + +import java.util.ArrayList; +import java.util.List; + +public class RoleMemberList extends Command { + + public RoleMemberList(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + String string = String.join(" ", args); + Role role = DiscordUtils.searchFirstRole(guild, string); + if (role == null) { + MessageFactory.create("Incorrect Usage! Example: " + commandLabel + " Member!").setColor(member.getColor()).queue(channel); + return; + } + List roleMembers = guild.getMembersWithRoles(role); + if (roleMembers.isEmpty()) { + MessageFactory.create("Could not find any users with the role " + role.getName()).setColor(member.getColor()).queue(channel); + return; + } + StringBuilder builder = new StringBuilder("Users With Role `").append(role.getName()).append("`: "); + List membersWithRole = new ArrayList<>(); + roleMembers.forEach(roleMember -> membersWithRole.add(format(roleMember))); + builder.append(String.join(", ", membersWithRole)); + MessageFactory.create(builder.toString().trim()).setColor(member.getColor()).queue(channel); + } + + private String format(Member member) { + String name = member.getUser().getName() + "#" + member.getUser().getDiscriminator(); + if (member.getNickname() != null && !member.getNickname().isEmpty()) { + name = name + String.format(" [%s]", member.getNickname()); + } + return name; + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/ServerInfoCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/ServerInfoCommand.java index 32af2c4..9a1eeb2 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/general/ServerInfoCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/general/ServerInfoCommand.java @@ -5,6 +5,9 @@ import io.rixa.bot.commands.perms.RixaPermission; import io.rixa.bot.guild.RixaGuild; import io.rixa.bot.guild.manager.GuildManager; import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.User; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; @@ -17,25 +20,25 @@ public class ServerInfoCommand extends Command { } @Override - public void execute(GuildMessageReceivedEvent event) { - RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"); - User owner = event.getGuild().getOwner().getUser(); + User owner = guild.getOwner().getUser(); MessageFactory .create(rixaGuild.getDescription()) - .setTitle(event.getGuild().getName(), String.format("http://rixa.io/servers/%s", event.getGuild().getId())) - .addField("Created", event.getGuild().getCreationTime().format(formatter), true) - .addField("Region", event.getGuild().getRegion().toString(), true) - .addField("Users", String.valueOf(event.getGuild().getMembers().size()), true) - .addField("Channel Categories", String.valueOf(event.getGuild().getCategories().size()), true) - .addField("Text Channels", String.valueOf(event.getGuild().getTextChannels().size()), true) - .addField("Voice Channels", String.valueOf(event.getGuild().getVoiceChannels().size()), true) - .addField("Verification Level", event.getGuild().getVerificationLevel().toString(), true) - .addField("Roles", String.valueOf(event.getGuild().getRoles().size()), true) + .setTitle(guild.getName(), String.format("http://rixa.io/servers/%s", guild.getId())) + .addField("Created", guild.getCreationTime().format(formatter), true) + .addField("Region", guild.getRegion().toString(), true) + .addField("Users", String.valueOf(guild.getMembers().size()), true) + .addField("Channel Categories", String.valueOf(guild.getCategories().size()), true) + .addField("Text Channels", String.valueOf(guild.getTextChannels().size()), true) + .addField("Voice Channels", String.valueOf(guild.getVoiceChannels().size()), true) + .addField("Verification Level", guild.getVerificationLevel().toString(), true) + .addField("Roles", String.valueOf(guild.getRoles().size()), true) .addField("Owner", owner.getName() + "#" + owner.getDiscriminator(), true) .addField("Enlisted", String.valueOf(true), true) - .setThumbnail(event.getGuild().getIconUrl()) - .footer("Server Id: " + event.getGuild().getId(), event.getGuild().getIconUrl()) - .queue(event.getChannel()); + .setThumbnail(guild.getIconUrl()) + .footer("Server Id: " + guild.getId(), guild.getIconUrl()) + .queue(channel); } } \ No newline at end of file diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/UrbanDictionaryCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/UrbanDictionaryCommand.java new file mode 100644 index 0000000..c3d3c22 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/UrbanDictionaryCommand.java @@ -0,0 +1,39 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.apis.UrbanDictionary; +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.MessageBuilder; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +public class UrbanDictionaryCommand extends Command { + + public UrbanDictionaryCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) throws IOException { + String searchQuery = String.join(" ", args); + UrbanDictionary urbanDictionary = null; + try { + urbanDictionary = new UrbanDictionary(URLEncoder.encode(searchQuery, "UTF-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + if(urbanDictionary == null || !urbanDictionary.search()) { + MessageFactory.create("Search term not found.").setColor(member.getColor()).queue(channel); + return; + } + MessageFactory.create(urbanDictionary.getDefinition()).setAuthor( + String.format("Definition: %s", urbanDictionary.getWordToSearch()), + "https://s-media-cache-ak0.pinimg.com/originals/f2/aa/37/f2aa3712516cfd0cf6f215301d87a7c2.jpg").setColor(member.getColor()).queue(channel); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/general/YoutubeCommand.java b/src/main/java/io/rixa/bot/commands/cmds/general/YoutubeCommand.java new file mode 100644 index 0000000..636f600 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/general/YoutubeCommand.java @@ -0,0 +1,29 @@ +package io.rixa.bot.commands.cmds.general; + +import io.rixa.bot.apis.YoutubeSearch; +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; + +import java.io.IOException; + +public class YoutubeCommand extends Command { + + public YoutubeCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + String searchQuery = String.join(" ", args); + try { + YoutubeSearch ytSearch = new YoutubeSearch(searchQuery); + channel.sendMessage(ytSearch.getUrl(0)).queue(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/moderator/ClearCommand.java b/src/main/java/io/rixa/bot/commands/cmds/moderator/ClearCommand.java new file mode 100644 index 0000000..c923f31 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/moderator/ClearCommand.java @@ -0,0 +1,76 @@ +package io.rixa.bot.commands.cmds.moderator; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.user.RixaUser; +import io.rixa.bot.utils.MessageFactory; +import io.rixa.bot.utils.Utils; +import lombok.Getter; +import net.dv8tion.jda.core.Permission; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.exceptions.PermissionException; + +import java.util.ArrayList; +import java.util.List; + +public class ClearCommand extends Command { + + @Getter + private RixaPermission rixaPermission; + public ClearCommand(String command, RixaPermission rixaPermission, String description, List aliases) { + super(command, rixaPermission, description, aliases); + this.rixaPermission = rixaPermission; + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + if (args == null || args.length == 0 || !Utils.isInteger(args[0])) { + MessageFactory.create(String.format("Incorrect Usage! Example: `%s%s 10`", rixaGuild.getSettings().getPrefix(), + commandLabel)).setColor(member.getColor()).queue(channel); + return; + } + RixaUser user = new RixaUser(); + if (!(user.hasPermission(rixaPermission))) { + MessageFactory.create("Sorry! You do not have permission for this command!").setColor(member.getColor()).queue(channel); + return; + } + int amount = Integer.parseInt(args[0]); + if (amount < 1 || amount > 100) { + MessageFactory.create("Please try a number less than 100 and greater than 1 and :grimacing:").setColor(member.getColor()).queue(channel); + return; + } + int i = deleteMessages(channel, amount); + MessageFactory.create("Successfully deleted *" + i + "* messages in " + channel.getAsMention()) + .footer("Requested by: " + member.getEffectiveName(), member.getUser().getEffectiveAvatarUrl()) + .setColor(member.getColor()) + .queue(channel); + } + + private int deleteMessages(TextChannel channel, int amount) { + List messageHistory= channel.getHistory().retrievePast(amount).complete(); + List pinnedMessages = channel.getPinnedMessages().complete(); + List newMessages = new ArrayList<>(); + int i = 0; + messageHistory.forEach(message -> { + if (!(pinnedMessages.contains(message))) { + newMessages.add(message); + } + }); + // !mute Savvy 10s Hello Savvy! + try { + channel.deleteMessages(newMessages).queue(); + i++; + } catch (PermissionException ex) { + if (ex.getPermission() == Permission.MESSAGE_MANAGE) + MessageFactory.create("I do not have permission to clear messages within this channel!").queue(channel); + } catch (IllegalArgumentException ignored) { + } + return i; + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/moderator/MuteCommand.java b/src/main/java/io/rixa/bot/commands/cmds/moderator/MuteCommand.java new file mode 100644 index 0000000..fc6f44b --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/moderator/MuteCommand.java @@ -0,0 +1,41 @@ +package io.rixa.bot.commands.cmds.moderator; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.DiscordUtils; +import io.rixa.bot.utils.MessageFactory; +import io.rixa.bot.utils.Utils; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; + +public class MuteCommand extends Command { + + private RixaPermission rixaPermission; + public MuteCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + this.rixaPermission = rixaPermission; + } + + @Override + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + // RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + String argumentString = String.join(" ", args); + Object[] objArray = DiscordUtils.memberSearchArray(guild, argumentString, false); + if (objArray.length == 0) { + MessageFactory.create("Could not find member!").setColor(member.getColor()).queue(channel); + } + Member targetMember = (Member) objArray[1]; + String targetMemberName = String.valueOf(objArray[0]); + if (targetMember == null) { + MessageFactory.create("Could not find member!").setColor(member.getColor()).queue(channel); + return; + } + argumentString = argumentString.replaceFirst(targetMemberName, "").trim(); + args = argumentString.split(" "); + String time = args[0].trim(); + argumentString = String.join(" ", args).replaceFirst(time, ""); + long milliseconds = Utils.toMilliSec(time); + MessageFactory.create("Duration: " + time + "\nReason: " + argumentString + "\nDuration in Milliseconds: " + milliseconds).queue(channel); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/other/ShutdownCommand.java b/src/main/java/io/rixa/bot/commands/cmds/other/ShutdownCommand.java index 289101e..e9cbba8 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/other/ShutdownCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/other/ShutdownCommand.java @@ -6,6 +6,9 @@ import io.rixa.bot.commands.perms.RixaPermission; import io.rixa.bot.guild.RixaGuild; import io.rixa.bot.guild.manager.GuildManager; import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; public class ShutdownCommand extends Command { @@ -15,13 +18,14 @@ public class ShutdownCommand extends Command { } @Override - public void execute(GuildMessageReceivedEvent event) { - if (!(Rixa.getInstance().getConfiguration().isBotAdmin(event.getAuthor().getId()))) { - new MessageFactory(event.getMember().getAsMention() + ", you do not have permission for this command.").setColor(event.getMember().getColor()).queue(event.getChannel()); + public void execute(String commandLabel, Guild guild, Member member, TextChannel channel, String[] args) { + if (!(Rixa.getInstance().getConfiguration().isBotAdmin(member.getUser().getId()))) { + new MessageFactory(member.getAsMention() + + ", you do not have permission for this command.").setColor(member.getColor()).queue(channel); return; } try { - MessageFactory.create("Shutting down...").queue(event.getChannel()); + MessageFactory.create("Shutting down...").selfDestruct(0).queue(channel); for (RixaGuild rixaGuild : GuildManager.getInstance().getGuilds().values()) { Thread.sleep(50); rixaGuild.save(); diff --git a/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java b/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java index 1230350..d0fa928 100644 --- a/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java +++ b/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java @@ -22,7 +22,7 @@ public class CommandHandler { } public Command getCommand(String commandName) throws CommandNotFoundException { - if (commandMap.containsKey(commandName)) return commandMap.get(commandName); + if (commandMap.containsKey(commandName.toLowerCase())) return commandMap.get(commandName.toLowerCase()); for(Command command: commandMap.values()) { if (command.getAliases().contains(commandName)) { return command; diff --git a/src/main/java/io/rixa/bot/data/config/Configuration.java b/src/main/java/io/rixa/bot/data/config/Configuration.java index dd9a267..dcaf70e 100644 --- a/src/main/java/io/rixa/bot/data/config/Configuration.java +++ b/src/main/java/io/rixa/bot/data/config/Configuration.java @@ -11,7 +11,7 @@ public class Configuration { @Getter @Setter private Map sqlCredentials; @Getter @Setter private List botAdmins; @Getter @Setter private String token, botGame; - @Getter @Setter private int shards; + @Getter @Setter private int shards = 1; public Configuration() {} diff --git a/src/main/java/io/rixa/bot/data/storage/enums/Statements.java b/src/main/java/io/rixa/bot/data/storage/enums/Statements.java index 2de1ef0..04951e9 100644 --- a/src/main/java/io/rixa/bot/data/storage/enums/Statements.java +++ b/src/main/java/io/rixa/bot/data/storage/enums/Statements.java @@ -7,8 +7,8 @@ public enum Statements { /* Select statements */ - SELECT_CORE("SELECT * FROM `core` WHERE `guild_id` = ?"), SELECT_MODULE_STATUS("SELECT `{module_name}` FROM `modules` WHERE `guild_id` = ?"), + SELECT_ALL_FROM_TABLE("SELECT * FROM `{table_name}` WHERE `guild_id` = ?"), /* diff --git a/src/main/java/io/rixa/bot/events/BotJoinListener.java b/src/main/java/io/rixa/bot/events/BotJoinListener.java index 5606eac..6a4b63a 100644 --- a/src/main/java/io/rixa/bot/events/BotJoinListener.java +++ b/src/main/java/io/rixa/bot/events/BotJoinListener.java @@ -8,7 +8,6 @@ public class BotJoinListener { @SubscribeEvent public void onJoin(GuildJoinEvent event) { - System.out.println("GuildJoinEvent Event"); event.getJDA().getGuilds().forEach(guild -> GuildManager.getInstance().addGuild(guild)); } } diff --git a/src/main/java/io/rixa/bot/events/MessageListener.java b/src/main/java/io/rixa/bot/events/MessageListener.java index 2531cf6..59b8382 100644 --- a/src/main/java/io/rixa/bot/events/MessageListener.java +++ b/src/main/java/io/rixa/bot/events/MessageListener.java @@ -12,11 +12,12 @@ import net.dv8tion.jda.core.events.ReadyEvent; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.core.hooks.SubscribeEvent; +import java.io.IOException; + public class MessageListener { @SubscribeEvent public void onMessage(GuildMessageReceivedEvent event) { - System.out.println("GuildMessageReceivedEvent Event"); String message = event.getMessage().getContent().trim(); RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); if (message.startsWith("@" + event.getGuild().getSelfMember().getEffectiveName())) { @@ -25,16 +26,21 @@ public class MessageListener { } String prefix = "!"; if (!(message.startsWith(prefix))) return; - String commandName = (message.contains(" ") ? message.split(" ")[0] : message); - command(commandName, prefix, event); + String[] msgArgs = message.split(" "); + String commandName = (message.contains(" ") ? msgArgs[0] : message); + String[] args = new String[msgArgs.length - 1]; + System.arraycopy(msgArgs, 1, args, 0, msgArgs.length - 1); + command(commandName, prefix, event, args); } - private void command(String commandName, String prefix, GuildMessageReceivedEvent event) { + private void command(String commandName, String prefix, GuildMessageReceivedEvent event, String[] args) { commandName = commandName.replaceFirst(prefix, ""); try { Command command = Rixa.getInstance().getCommandHandler().getCommand(commandName); - command.execute(event); - } catch (CommandNotFoundException ignored) {} + //command.execute(event); + event.getMessage().delete().queue(); + command.execute(commandName, event.getGuild(), event.getMember(), event.getChannel(), args); + } catch (CommandNotFoundException | IOException ignored) { } } private void chatter(RixaGuild rixaGuild, TextChannel channel, String message) { diff --git a/src/main/java/io/rixa/bot/events/UserListener.java b/src/main/java/io/rixa/bot/events/UserListener.java new file mode 100644 index 0000000..7c5fb63 --- /dev/null +++ b/src/main/java/io/rixa/bot/events/UserListener.java @@ -0,0 +1,85 @@ +package io.rixa.bot.events; + +import io.rixa.bot.Rixa; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.MessageReaction; +import net.dv8tion.jda.core.events.guild.member.GuildMemberJoinEvent; +import net.dv8tion.jda.core.events.guild.member.GuildMemberLeaveEvent; +import net.dv8tion.jda.core.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.core.events.message.priv.react.PrivateMessageReactionAddEvent; +import net.dv8tion.jda.core.hooks.SubscribeEvent; + +public class UserListener { + + @SubscribeEvent + public void onJoin(GuildMemberJoinEvent event) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); + if (!rixaGuild.getSettings().getJoinMessage().equalsIgnoreCase("default_value")) { + MessageFactory.create(rixaGuild.getSettings().getJoinMessage() + .replace("%guild%", event.getGuild().getName()) + .replace("%user%", event.getUser().getName()) + .replace("%joinPosition%", String.valueOf(event.getGuild().getMembers().size()))) + .selfDestruct(0).send(event.getUser()); + } + if (!rixaGuild.getSettings().isJoinVerification()) { + return; + } + if (!rixaGuild.getConfirmationUsers().contains(event.getUser().getId())) { + rixaGuild.getConfirmationUsers().add(event.getUser().getId()); + } + MessageFactory.create(rixaGuild.getSettings().getJoinPrivateMessage() + .replace("%guild%", event.getGuild().getName()) + .replace("%user%", event.getUser().getName()) + .replace("%joinPosition%", String.valueOf(event.getGuild().getMembers().size()))) + .selfDestruct(0).addReaction("thumbsUp").addReaction("thumbsDown").send(event.getUser()); + } + + @SubscribeEvent + public void onAddReactionPM(PrivateMessageReactionAddEvent event) { + if (event.getUser().isBot()) return; + String messageId = event.getMessageId(); + Message message = event.getChannel().getMessageById(messageId).complete(); + if (message == null || message.getEmbeds().size() == 0) return; + if (!event.getReaction().getReactionEmote().getName().contains("thumbsUp") && + !event.getReaction().getReactionEmote().getName().contains("thumbsDown")) { + System.out.println("Neither reaction added although this was: " + event.getReaction().getReactionEmote().getName()); + return; + } + // Add check to see if reaction added is a thumbs up or down + MessageEmbed messageEmbed = message.getEmbeds().get(0); + if (messageEmbed.getFooter() == null || messageEmbed.getFooter().getText().isEmpty()) return; + String guildId = messageEmbed.getFooter().getText(); + Guild guild = null; + for (JDA jda : Rixa.getInstance().getShardList()) { + if (jda.getGuildById(guildId) != null) { + guild = jda.getGuildById(guildId); + } + } + if (guild == null) return; + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(guild); + if (!rixaGuild.getConfirmationUsers().contains(event.getUser().getId())) return; + rixaGuild.getConfirmationUsers().remove(event.getUser().getId()); + guild.getController().addRolesToMember(guild.getMember(event.getUser()), rixaGuild.getSettings().getDefaultRole()).queue(); + } + + @SubscribeEvent + public void onQuit(GuildMemberLeaveEvent event) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); + if (rixaGuild.getConfirmationUsers().contains(event.getUser().getId())) { + rixaGuild.getConfirmationUsers().remove(event.getUser().getId()); + } + if (!rixaGuild.getSettings().getJoinMessage().equalsIgnoreCase("default_value")) { + MessageFactory.create(rixaGuild.getSettings().getQuitMessage() + .replace("%guild%", event.getGuild().getName()) + .replace("%user%", event.getUser().getName()) + .replace("%joinPosition%", String.valueOf(event.getGuild().getMembers().size()))) + .selfDestruct(0).send(event.getUser()); + } + } +} diff --git a/src/main/java/io/rixa/bot/guild/RixaGuild.java b/src/main/java/io/rixa/bot/guild/RixaGuild.java index 3caa144..e39009a 100644 --- a/src/main/java/io/rixa/bot/guild/RixaGuild.java +++ b/src/main/java/io/rixa/bot/guild/RixaGuild.java @@ -1,9 +1,10 @@ package io.rixa.bot.guild; -import io.rixa.bot.Rixa; import io.rixa.bot.guild.manager.IGuild; import io.rixa.bot.guild.modules.RixaModule; import io.rixa.bot.guild.modules.module.ConversationModule; +import io.rixa.bot.guild.modules.module.MusicModule; +import io.rixa.bot.guild.settings.Settings; import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.core.entities.Guild; @@ -16,22 +17,29 @@ import java.util.Map; public class RixaGuild implements IGuild { @Getter private final Map modules; + @Getter private List confirmationUsers; @Getter @Setter private List keywords; @Getter @Setter private String description; @Getter private final String id; @Getter private Guild guild; + @Getter private Settings settings; public RixaGuild(Guild guild) { this.guild = guild; id = guild.getId(); modules = new HashMap<>(); keywords = new ArrayList<>(); + confirmationUsers = new ArrayList<>(); load(); } @Override public void load() { - registerModule(new ConversationModule("Conversation", "Have a conversation with Rixa!")); + registerModules( + new ConversationModule("Conversation", "Have a conversation with Rixa!", this), + new MusicModule("Music", "Listen to music from within discord!", this) + ); + settings = new Settings(this); } @Override @@ -42,6 +50,11 @@ public class RixaGuild implements IGuild { return modules.get(id); } + private void registerModules(RixaModule... modules) { + for (RixaModule module : modules) { + registerModule(module); + } + } @Override public RixaModule registerModule(RixaModule module) { if (!(isRegistered(module.getName()))) modules.put(module.getName(), module); diff --git a/src/main/java/io/rixa/bot/guild/manager/GuildManager.java b/src/main/java/io/rixa/bot/guild/manager/GuildManager.java index 677e8ef..fea62a2 100644 --- a/src/main/java/io/rixa/bot/guild/manager/GuildManager.java +++ b/src/main/java/io/rixa/bot/guild/manager/GuildManager.java @@ -1,9 +1,9 @@ package io.rixa.bot.guild.manager; -import gnu.trove.map.TByteByteMap; import io.rixa.bot.data.storage.DatabaseAdapter; import io.rixa.bot.data.storage.enums.Statements; import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.mapper.GuildMapper; import net.dv8tion.jda.core.entities.Guild; import java.util.HashMap; @@ -44,7 +44,7 @@ public class GuildManager { RixaGuild rixaGuild = new RixaGuild(guild); rixaGuildMap.put(guild.getId(), rixaGuild); DatabaseAdapter.getInstance().get().queryForObject( - Statements.SELECT_CORE.getStatement(), new Object[] { guild.getId() }, new GuildMapper()); + Statements.SELECT_ALL_FROM_TABLE.getStatement("{table_name}", "core"), new Object[] { guild.getId() }, new GuildMapper()); return rixaGuild; } diff --git a/src/main/java/io/rixa/bot/guild/manager/RixaSettings.java b/src/main/java/io/rixa/bot/guild/manager/RixaSettings.java new file mode 100644 index 0000000..4b8d9a7 --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/manager/RixaSettings.java @@ -0,0 +1,9 @@ +package io.rixa.bot.guild.manager; + +public interface RixaSettings { + + String getPrefix(); + + void load(); + void save(); +} diff --git a/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java b/src/main/java/io/rixa/bot/guild/mapper/GuildMapper.java similarity index 89% rename from src/main/java/io/rixa/bot/guild/manager/GuildMapper.java rename to src/main/java/io/rixa/bot/guild/mapper/GuildMapper.java index 222513c..fadec3e 100644 --- a/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java +++ b/src/main/java/io/rixa/bot/guild/mapper/GuildMapper.java @@ -1,5 +1,7 @@ -package io.rixa.bot.guild.manager; +package io.rixa.bot.guild.mapper; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.guild.manager.IGuild; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; diff --git a/src/main/java/io/rixa/bot/guild/modules/RixaModule.java b/src/main/java/io/rixa/bot/guild/modules/RixaModule.java index 9efdd94..9d05159 100644 --- a/src/main/java/io/rixa/bot/guild/modules/RixaModule.java +++ b/src/main/java/io/rixa/bot/guild/modules/RixaModule.java @@ -1,5 +1,8 @@ package io.rixa.bot.guild.modules; +import io.rixa.bot.Rixa; +import io.rixa.bot.guild.RixaGuild; + public interface RixaModule { String getName(); @@ -8,4 +11,5 @@ public interface RixaModule { void load(); void save(); void reload(); + RixaGuild getGuild(); } diff --git a/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java b/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java index 2144c26..bb0da1c 100644 --- a/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java +++ b/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java @@ -6,6 +6,7 @@ import com.google.code.chatterbotapi.ChatterBotSession; import com.google.code.chatterbotapi.ChatterBotType; import io.rixa.bot.data.storage.DatabaseAdapter; import io.rixa.bot.data.storage.enums.Statements; +import io.rixa.bot.guild.RixaGuild; import io.rixa.bot.guild.modules.RixaModule; import lombok.Getter; import lombok.Setter; @@ -16,12 +17,14 @@ public class ConversationModule implements RixaModule { @Getter private ChatterBotSession chatBotSession; @Getter private ChatterBot chatBot; @Getter private String name, description; + @Getter private RixaGuild guild; @Getter @Setter boolean enabled; - public ConversationModule(String name, String description) { + public ConversationModule(String name, String description, RixaGuild guild) { this.name = name; this.description = description; this.enabled = true; + this.guild = guild; } @Override diff --git a/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java b/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java index b7c8981..31d2d15 100644 --- a/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java +++ b/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java @@ -1,5 +1,6 @@ package io.rixa.bot.guild.modules.module; +import io.rixa.bot.guild.RixaGuild; import io.rixa.bot.guild.modules.RixaModule; import lombok.Getter; import lombok.Setter; @@ -8,10 +9,12 @@ public class LevelsModule implements RixaModule { @Getter private String name, description; @Getter @Setter boolean enabled; + @Getter private RixaGuild guild; - public LevelsModule(String name, String description) { + public LevelsModule(String name, String description, RixaGuild rixaGuild) { this.name = name; this.description = description; + this.guild = rixaGuild; } @Override diff --git a/src/main/java/io/rixa/bot/guild/modules/module/MusicModule.java b/src/main/java/io/rixa/bot/guild/modules/module/MusicModule.java new file mode 100644 index 0000000..c3f8032 --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/modules/module/MusicModule.java @@ -0,0 +1,55 @@ +package io.rixa.bot.guild.modules.module; + +import io.rixa.bot.Rixa; +import io.rixa.bot.data.storage.DatabaseAdapter; +import io.rixa.bot.data.storage.enums.Statements; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.guild.modules.RixaModule; +import io.rixa.bot.guild.modules.module.music.MusicManager; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.core.entities.Role; + +public class MusicModule implements RixaModule { + + @Getter private String name, description; + @Getter @Setter private Role musicRole; + @Getter @Setter boolean enabled; + @Getter @Setter private MusicManager musicManager; + @Getter private RixaGuild guild; + + public MusicModule(String name, String description, RixaGuild guild) { + this.name = name; + this.description = description; + this.enabled = true; + this.guild = guild; + } + + @Override + public void load() { + setEnabled(DatabaseAdapter.getInstance().get().queryForObject + (Statements.SELECT_MODULE_STATUS.getStatement("{module_name}", getName()), + new Object[]{name}, (resultSet, i) -> resultSet.getBoolean("enabled"))); + reload(); + } + + @Override + public void save() { + // Check & Set if enabled; + DatabaseAdapter.getInstance().get().update("UPDATE `modules` SET `music` = ? WHERE `guild_id` = ?", enabled, guild.getId()); + DatabaseAdapter.getInstance().get().update("UPDATE `music` SET `music_role` = ? WHERE `guild_id` = ?", musicRole.getId(), guild.getId()); + } + + @Override + public void reload() { + if (!isEnabled()) return; + DatabaseAdapter.getInstance().get().queryForObject(Statements.SELECT_ALL_FROM_TABLE.getStatement("{table}", "music"), + new Object[] { guild.getId() }, (resultSet, i) -> { + if (guild.getGuild().getRoleById(resultSet.getString("music_role")) != null) { + this.musicRole = guild.getGuild().getRoleById(resultSet.getString("music_role")); + } + return 0; + }); + } +} diff --git a/src/main/java/io/rixa/bot/guild/modules/module/music/AudioPlayerSendHandler.java b/src/main/java/io/rixa/bot/guild/modules/module/music/AudioPlayerSendHandler.java new file mode 100644 index 0000000..47b8dd3 --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/modules/module/music/AudioPlayerSendHandler.java @@ -0,0 +1,44 @@ +package io.rixa.bot.guild.modules.module.music; + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; +import lombok.Getter; +import net.dv8tion.jda.core.audio.AudioSendHandler; + +public class AudioPlayerSendHandler implements AudioSendHandler { + @Getter private final AudioPlayer audioPlayer; + private AudioFrame lastFrame; + + /** + * @param audioPlayer Audio player to wrap. + */ + public AudioPlayerSendHandler(AudioPlayer audioPlayer) { + this.audioPlayer = audioPlayer; + } + + @Override + public boolean canProvide() { + if (lastFrame == null) { + lastFrame = audioPlayer.provide(); + } + return lastFrame != null; + } + + @Override + public byte[] provide20MsAudio() { + if (lastFrame == null) + { + lastFrame = audioPlayer.provide(); + } + + byte[] data = lastFrame != null ? lastFrame.data : null; + lastFrame = null; + + return data; + } + + @Override + public boolean isOpus() { + return true; + } +} diff --git a/src/main/java/io/rixa/bot/guild/modules/module/music/MusicManager.java b/src/main/java/io/rixa/bot/guild/modules/module/music/MusicManager.java new file mode 100644 index 0000000..bec212f --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/modules/module/music/MusicManager.java @@ -0,0 +1,32 @@ +package io.rixa.bot.guild.modules.module.music; + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; +import lombok.Getter; + +public class MusicManager { + /** + * Audio player for the guild. + */ + @Getter private final AudioPlayer player; + /** + * Track scheduler for the player. + */ + @Getter private final TrackScheduler scheduler; + /** + * Wrapper around AudioPlayer to use it as an AudioSendHandler. + */ + @Getter private final AudioPlayerSendHandler sendHandler; + + /** + * Creates a player and a track scheduler. + * + * @param manager Audio player manager to use for creating the player. + */ + public MusicManager(AudioPlayerManager manager) { + player = manager.createPlayer(); + scheduler = new TrackScheduler(player); + sendHandler = new AudioPlayerSendHandler(player); + player.addListener(scheduler); + } +} diff --git a/src/main/java/io/rixa/bot/guild/modules/module/music/TrackScheduler.java b/src/main/java/io/rixa/bot/guild/modules/module/music/TrackScheduler.java new file mode 100644 index 0000000..c53cf1b --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/modules/module/music/TrackScheduler.java @@ -0,0 +1,81 @@ +package io.rixa.bot.guild.modules.module.music; + +import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; +import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; +import io.rixa.bot.pagination.ObjectPagination; +import io.rixa.bot.pagination.QueuePagination; +import lombok.Getter; +import lombok.Setter; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class TrackScheduler extends AudioEventAdapter { + @Getter @Setter private boolean repeating = false, playlistRepeat = false; + @Getter private final AudioPlayer player; + @Getter private final Queue queue; + @Getter private AudioTrack lastTrack; + @Getter private QueuePagination queuePagination; + + /** + * @param player The audio player this scheduler uses + */ + public TrackScheduler(AudioPlayer player) { + this.player = player; + this.queue = new LinkedList<>(); + queuePagination = new QueuePagination(queue, 5); + } + + /** + * Add the next track to queue or play right away if nothing is in the queue. + * + * @param track The track to play or add to queue. + */ + public void queue(AudioTrack track) { + // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If + // something is playing, it returns false and does nothing. In that case the player was already playing so this + // track goes to the queue instead. + if (!player.startTrack(track, true)) { + queue.offer(track); + } + queuePagination.updateList(queue); + } + + /** + * Start the next track, stopping the current one if it is playing. + */ + public AudioTrack nextTrack() { + // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are + // giving null to startTrack, which is a valid argument and will simply stop the player. + AudioTrack track = queue.poll(); + player.startTrack(track, false); + queuePagination.updateList(queue); + return track; + } + + @Override + public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { + this.lastTrack = track; + // Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED) + if (endReason.mayStartNext) { + if (repeating) + player.startTrack(lastTrack.makeClone(), false); + else { + if (playlistRepeat) { + queue(lastTrack.makeClone()); + } + nextTrack(); + } + } + + } + + public void shuffle() { + Collections.shuffle((List) queue); + queuePagination.updateList(queue); + } +} diff --git a/src/main/java/io/rixa/bot/guild/settings/Settings.java b/src/main/java/io/rixa/bot/guild/settings/Settings.java new file mode 100644 index 0000000..82acc70 --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/settings/Settings.java @@ -0,0 +1,60 @@ +package io.rixa.bot.guild.settings; + +import io.rixa.bot.data.storage.DatabaseAdapter; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.RixaSettings; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.core.entities.Role; +import net.dv8tion.jda.core.entities.TextChannel; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Settings implements RixaSettings { + + @Getter @Setter private String prefix, joinMessage, quitMessage, joinPrivateMessage; + @Getter @Setter private boolean joinVerification; + @Getter @Setter private TextChannel greetings, farewell; + @Getter @Setter private Role muteRole, defaultRole; + @Getter private RixaGuild rixaGuild; + + public Settings(RixaGuild rixaGuild) { + this.rixaGuild = rixaGuild; + } + + @Override + public void load() { + DatabaseAdapter.getInstance().get().query("SELECT * FROM `settings` WHERE `guild_id` = ?", + new Object[] { rixaGuild.getId() }, (resultSet, i) -> { + setPrefix(resultSet.getString("prefix")); + setJoinMessage(resultSet.getString("joinMessage")); + setJoinMessage(resultSet.getString("quitMessage")); + setJoinPrivateMessage(resultSet.getString("joinPm")); + setJoinVerification(resultSet.getBoolean("joinVerification")); + String greetingsId = resultSet.getString("greetings"); + String farewellId = resultSet.getString("farewell"); + String defaultRoleId = resultSet.getString("defaultRole"); + String muteRoleId = resultSet.getString("muteRole"); + if (!greetingsId.equalsIgnoreCase("default_value") && rixaGuild.getGuild().getTextChannelById(greetingsId) != null) { + greetings = rixaGuild.getGuild().getTextChannelById(greetingsId); + } + if (!farewellId.equalsIgnoreCase("default_value") && rixaGuild.getGuild().getTextChannelById(farewellId) != null) { + farewell = rixaGuild.getGuild().getTextChannelById(farewellId); + } + if (!defaultRoleId.equalsIgnoreCase("default_value") && rixaGuild.getGuild().getRoleById(defaultRoleId) != null) { + defaultRole = rixaGuild.getGuild().getRoleById(defaultRoleId); + } + if (!muteRoleId.equalsIgnoreCase("default_value") && rixaGuild.getGuild().getRoleById(muteRoleId) != null) { + muteRole = rixaGuild.getGuild().getRoleById(muteRoleId); + } + return null; + }); + } + + @Override + public void save() { + + } +} diff --git a/src/main/java/io/rixa/bot/pagination/ObjectPagination.java b/src/main/java/io/rixa/bot/pagination/ObjectPagination.java new file mode 100644 index 0000000..51bd7f7 --- /dev/null +++ b/src/main/java/io/rixa/bot/pagination/ObjectPagination.java @@ -0,0 +1,35 @@ +package io.rixa.bot.pagination; + +import lombok.Getter; + +import java.util.Collections; +import java.util.List; + +public class ObjectPagination { + + @Getter private List objects; + @Getter private int maxPage, pageSize; + public ObjectPagination(List objects, int pageSize) { + this.objects = objects; + this.pageSize = pageSize; + this.maxPage = (objects.size() / pageSize + (objects.size() % pageSize)); + } + + public List getPage(int page) { + if(pageSize <= 0 || page <= 0) { + throw new IllegalArgumentException("Invalid page size: " + pageSize); + } + + int fromIndex = (page - 1) * pageSize; + if(objects == null || objects.size() < fromIndex){ + return Collections.emptyList(); + } + + // toIndex exclusive + return objects.subList(fromIndex, Math.min(fromIndex + pageSize, objects.size())); + } + + public void updateList(List obj) { + this.objects = obj; + } +} diff --git a/src/main/java/io/rixa/bot/pagination/QueuePagination.java b/src/main/java/io/rixa/bot/pagination/QueuePagination.java new file mode 100644 index 0000000..675c5dd --- /dev/null +++ b/src/main/java/io/rixa/bot/pagination/QueuePagination.java @@ -0,0 +1,46 @@ +package io.rixa.bot.pagination; + +import com.sedmelluq.discord.lavaplayer.track.AudioTrack; +import lombok.Getter; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class QueuePagination { + + @Getter private Queue objects; + @Getter List listObjects; + @Getter private int maxPage, pageSize; + public QueuePagination(Queue objects, int pageSize) { + this.objects = objects; + this.pageSize = pageSize; + this.maxPage = (objects.size() / pageSize + (objects.size() % pageSize)); + } + + public List getPage(int page) { + if(listObjects.isEmpty()) { + return Collections.emptyList(); + } + if(pageSize <= 0 || page <= 0) { + throw new IllegalArgumentException("Invalid page size: " + pageSize); + } + + int fromIndex = (page - 1) * pageSize; + if(objects.size() < fromIndex){ + return Collections.emptyList(); + } + // toIndex exclusive + return listObjects.subList(fromIndex, Math.min(fromIndex + pageSize, objects.size())); + } + + public List asList() { + return listObjects; + } + + public void updateList(Queue obj) { + this.objects = obj; + this.listObjects = new LinkedList<>(getObjects()); + } +} diff --git a/src/main/java/io/rixa/bot/user/RixaUser.java b/src/main/java/io/rixa/bot/user/RixaUser.java new file mode 100644 index 0000000..15ea926 --- /dev/null +++ b/src/main/java/io/rixa/bot/user/RixaUser.java @@ -0,0 +1,9 @@ +package io.rixa.bot.user; + +import io.rixa.bot.commands.perms.RixaPermission; + +public class RixaUser { + public boolean hasPermission(RixaPermission rixaPermission) { + return true; + } +} diff --git a/src/main/java/io/rixa/bot/utils/DiscordUtils.java b/src/main/java/io/rixa/bot/utils/DiscordUtils.java index 62b95ef..71021df 100644 --- a/src/main/java/io/rixa/bot/utils/DiscordUtils.java +++ b/src/main/java/io/rixa/bot/utils/DiscordUtils.java @@ -3,9 +3,12 @@ package io.rixa.bot.utils; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Role; +import net.dv8tion.jda.core.entities.VoiceChannel; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; public class DiscordUtils { @@ -29,26 +32,76 @@ public class DiscordUtils { || finalString.contains(member.getEffectiveName().toLowerCase()) || finalString.contains(member.getUser().getName().toLowerCase()) || finalString.equalsIgnoreCase(member.getEffectiveName().toLowerCase()) - || finalString.equalsIgnoreCase(member.getUser().getName().toLowerCase()) - ) { + || finalString.equalsIgnoreCase(member.getUser().getName().toLowerCase())) { if (!bots && member.getUser().isBot()) continue; members.add(member); } } - return members; } + public static Object[] memberSearchArray(Guild guild, String string, boolean bots) { + Object[] array = new Object[2]; + // First item is string, second is member + String finalString = string.toLowerCase().trim(); + for (Member member : guild.getMembers()) { + //String nameDescrim = member.getUser().getName().toLowerCase() + "#" + member.getUser().getDiscriminator().toLowerCase(); + if (finalString.contains(member.getUser().getName().toLowerCase() + "#" + member.getUser().getDiscriminator())) { + array[0] = member.getEffectiveName(); + array[1] = member; + break; + } else if (finalString.contains(member.getUser().getId())) { + array[0] = member.getEffectiveName(); + array[1] = member; + break; + }else if (finalString.contains(member.getEffectiveName().toLowerCase())) { + array[0] = member.getEffectiveName(); + array[1] = member; + break; + } else if (finalString.contains(member.getUser().getName().toLowerCase())) { + array[0] = member.getEffectiveName(); + array[1] = member; + break; + } + } + return array; + } + + public static Role searchFirstRole(Guild guild, String s) { + return roleSearch(guild, s).get(0); + } + public static List roleSearch(Guild guild, String string) { List roles = new ArrayList<>(); guild.getRoles().forEach(role -> { if (role.getName().toLowerCase().contains(string.toLowerCase()) || string.contains(role.getId()) - || string.toLowerCase().contains(role.getName().toLowerCase()) - ) + || string.toLowerCase().contains(role.getName().toLowerCase())) roles.add(role); }); return roles; } + + public static Role getMentionedRole(Guild guild, String string) { + Role mentionedRole = null; + for (Role role : guild.getRoles()) { + if (string.contains(role.getAsMention()) || string.contains("@" + role.getName())) { + mentionedRole = role; + break; + } + } + return mentionedRole; + } + + public static VoiceChannel voiceChannelSearch(Guild guild, String string) { + List voiceChannels = guild.getVoiceChannelsByName(string, true); + if (!voiceChannels.isEmpty()) { + return voiceChannels.get(0); + } + Optional optional = guild.getVoiceChannels().stream().sorted().filter(voiceChannel -> voiceChannel.getId().equalsIgnoreCase(string) || + voiceChannel.getName().equalsIgnoreCase(string) || + voiceChannel.getName().contains(string)).findFirst(); + return optional.orElse(null); + } } diff --git a/src/main/java/io/rixa/bot/utils/MessageFactory.java b/src/main/java/io/rixa/bot/utils/MessageFactory.java index 0f8215b..96e6832 100644 --- a/src/main/java/io/rixa/bot/utils/MessageFactory.java +++ b/src/main/java/io/rixa/bot/utils/MessageFactory.java @@ -47,6 +47,11 @@ public class MessageFactory { return this; } + public MessageFactory setImage(String image) { + builder.setImage(image); + return this; + } + public MessageFactory setColor(Color color) { builder.setColor(color); return this; @@ -67,6 +72,11 @@ public class MessageFactory { return this; } + public MessageFactory setAuthor(String name, String iconURL) { + builder.setAuthor(name, iconURL, iconURL); + return this; + } + public void queue(TextChannel channel) { try { message = channel.sendMessage(builder.build()).complete(true); diff --git a/src/main/java/io/rixa/bot/utils/Utils.java b/src/main/java/io/rixa/bot/utils/Utils.java new file mode 100644 index 0000000..cd024a2 --- /dev/null +++ b/src/main/java/io/rixa/bot/utils/Utils.java @@ -0,0 +1,61 @@ +package io.rixa.bot.utils; + +public class Utils { + + public static boolean isInteger(String s) { + return isInteger(s,10); + } + + public static boolean isInteger(String s, int radix) { + if(s.isEmpty()) return false; + for(int i = 0; i < s.length(); i++) { + if(i == 0 && s.charAt(i) == '-') { + if(s.length() == 1) return false; + else continue; + } + if(Character.digit(s.charAt(i),radix) < 0) return false; + } + return true; + } + + public static long toMilliSec(String s) { + // This is not my regex :P | From: http://stackoverflow.com/a/8270824 + String[] sl = s.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); + + long i = Long.parseLong(sl[0]); + switch (sl[1]) { + case "seconds": + case "second": + case "sec": + case "s": + return i * 1000; + case "minutes": + case "min": + case "minute": + case "m": + return i * 1000 * 60; + case "hours": + case "hour": + case "hr": + case "h": + return i * 1000 * 60 * 60; + case "days": + case "day": + case "dy": + case "d": + return i * 1000 * 60 * 60 * 24; + case "weeks": + case "week": + case "wk": + case "w": + return i * 1000 * 60 * 60 * 24 * 7; + case "months": + case "month": + case "mnth": + case "mo": + return i * 1000 * 60 * 60 * 24 * 30; + default: + return -1; + } + } +} diff --git a/src/main/java/io/rixa/bot/utils/WebUtil.java b/src/main/java/io/rixa/bot/utils/WebUtil.java new file mode 100644 index 0000000..a144bc6 --- /dev/null +++ b/src/main/java/io/rixa/bot/utils/WebUtil.java @@ -0,0 +1,41 @@ +package io.rixa.bot.utils; + + +import io.rixa.bot.Rixa; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class WebUtil { + + public static String getWebPage(String url) throws IOException { + URL searchURL = new URL(url); + HttpURLConnection conn = (HttpURLConnection) searchURL.openConnection(); + return getWebPage(conn); + } + + public static String getWebPage(HttpURLConnection conn) throws IOException { + StringBuilder sb = new StringBuilder(); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); + conn.setRequestProperty("Referer", "http://www.google.com"); + + int response = conn.getResponseCode(); + if (response == 403) { + Rixa.getInstance().getLogger().info("Quota Exceeded"); + } else if (response != 200) { + Rixa.getInstance().getLogger().info("DEBUG: Response code: " + response); + } + + BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + sb.append(line).append("\n"); + } + in.close(); + + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/test/java/Main.java b/src/test/java/Main.java new file mode 100644 index 0000000..86d48bb --- /dev/null +++ b/src/test/java/Main.java @@ -0,0 +1,53 @@ +import java.util.*; + +public class Main { + + private static List list = new ArrayList<>(); + public static void main(String[] args) { + if (list.isEmpty()) { + for (int i = 0; i < 25; i++) { + list.add("Item No. " + (i + 1)); + } + } + List page = getPage(list, 3, 5); + System.out.println("Page: " + (3)); + page.forEach(System.out::println); + List> pages = getPages(list, 5); + + page = pages.get(2); + System.out.println("Page: " + (3)); + page.forEach(System.out::println); + /*for(int i = 0; i < pages.size(); i++) { + List page = pages.get(i); + System.out.println("Page: " + (i + 1)); + page.forEach(System.out::println); + }*/ + } + + public static List getPage(List sourceList, int page, int pageSize) { + if(pageSize <= 0 || page <= 0) { + throw new IllegalArgumentException("invalid page size: " + pageSize); + } + + int fromIndex = (page - 1) * pageSize; + if(sourceList == null || sourceList.size() < fromIndex){ + return Collections.emptyList(); + } + + // toIndex exclusive + return sourceList.subList(fromIndex, Math.min(fromIndex + pageSize, sourceList.size())); + } + + public static List> getPages(Collection c, Integer pageSize) { + if (c == null) + return Collections.emptyList(); + List list = new ArrayList<>(c); + if (pageSize == null || pageSize <= 0 || pageSize > list.size()) + pageSize = list.size(); + int numPages = (int) Math.ceil((double)list.size() / (double)pageSize); + List> pages = new ArrayList<>(numPages); + for (int pageNum = 0; pageNum < numPages;) + pages.add(list.subList(pageNum * pageSize, Math.min(++pageNum * pageSize, list.size()))); + return pages; + } +}