Page MenuHomedesp's stash

No OneTemporary

diff --git a/src/me/despawningbone/discordbot/DiscordBot.java b/src/me/despawningbone/discordbot/DiscordBot.java
index a37ec66..c77a14a 100644
--- a/src/me/despawningbone/discordbot/DiscordBot.java
+++ b/src/me/despawningbone/discordbot/DiscordBot.java
@@ -1,290 +1,269 @@
package me.despawningbone.discordbot;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import javax.security.auth.login.LoginException;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.PropertyConfigurator;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import com.sedmelluq.discord.lavaplayer.jdaudp.NativeAudioSendFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import me.despawningbone.discordbot.command.Command;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.requests.GatewayIntent;
public class DiscordBot {
- // TODO move to appropriate locations
-
- //public static List<String> BannedID = new ArrayList<String>(); //DONE store in DB
+ //TODO move to appropriate locations
+
public static List<String> ModID = new ArrayList<String>();
public static List<String> logExcemptID = new ArrayList<String>();
//TODO synchronize below or change to concurrent //but why? its thread safe since its read only
public static HashMap<String, Command> commands = new HashMap<String, Command>();
public static HashMap<String, Command> aliases = new HashMap<String, Command>(); //TODO temporary solution
public static TreeMap<String, List<Command>> catCmds = new TreeMap<String, List<Command>>(); //order base on categories?
public static ConcurrentHashMap<String, TextChannel> lastMusicCmd = new ConcurrentHashMap<String, TextChannel>(); //TODO store in guild configs //nah its fine
- //public static HashMap<String, Game> guildMemberPresence = new HashMap<String, Game>();
-
public static final String prefix = "!desp "; //DONE allow guild change prefix?
public static JDA mainJDA = null;
public static String BotID;
public static String OwnerID;
public static Properties tokens = new Properties();
static final Logger logger = LoggerFactory.getLogger(DiscordBot.class); //package private
public static HikariDataSource db;
- /*public static FirefoxDriver driver;*/
-
- // DONE SQLite integration; check if program termination will screw up the connection
- // TODO SHARDING
- // DONE on shutdown alert those playing music or await? //alerted
+ //DONE SQLite integration; check if program termination will screw up the connection
+ //TODO SHARDING
+ //DONE on shutdown alert those playing music or await? //alerted
public static void main(String[] args) {
- // initiate Selenium
- /*System.setProperty("webdriver.gecko.driver",
- System.getProperty("user.dir") + File.separator + "geckodriver.exe");
- FirefoxOptions options = new FirefoxOptions();
- options.setHeadless(true);
- driver = new FirefoxDriver(options);*/
PropertyConfigurator.configure(System.getProperty("user.dir") + File.separator + "log4j.properties");
+ //init tokens file
try(FileInputStream in = new FileInputStream(new File(System.getProperty("user.dir") + File.separator + "tokens.properties"))){
tokens.load(in);
} catch (IOException e) {
e.printStackTrace();
return;
}
initCmds();
initDB();
- // login
+ //login
try {
JDA jda = JDABuilder.create(tokens.getProperty("bot"), GatewayIntent.getIntents(GatewayIntent.ALL_INTENTS))
//.setAudioSendFactory(new NativeAudioSendFactory()) //segfaults frequently somehow, disabling
.addEventListeners(new me.despawningbone.discordbot.EventListener()).build();
jda.getPresence().setActivity(Activity.watching("Ping me for info!"));
// for user bots, see
// https://discordapp.com/developers/docs/topics/gateway#update-status
// and
// https://gist.github.com/MrPowerGamerBR/b8acccb9951b0d78a5115024e3ee0d03
//find owner id from bot owner
BotID = jda.getSelfUser().getId();
OwnerID = jda.retrieveApplicationInfo().complete().getOwner().getId();
} catch (LoginException e) {
e.printStackTrace();
return;
}
- // initiate logs //handled by log4j?
+ //initiate logs //handled by log4j?
File directory = new File(System.getProperty("user.dir") + File.separator + "logs" + File.separator);
if (!directory.exists()) {
directory.mkdir();
}
-
- //initiate test anime pics cache for repost check
- /*try {
- FileInputStream in = new FileInputStream(System.getProperty("user.dir") + File.separator + "testAnimePicCache.bin");
- ObjectInputStream ois = new ObjectInputStream(in);
- EventListener.testAnimePicCache = (Multimap<String, String>) ois.readObject();
- ois.close();
- } catch (IOException | ClassNotFoundException e) {
- e.printStackTrace();
- }
-
- Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> { //no need to be a global variable since i dont need to access it
- try {
- FileOutputStream out = new FileOutputStream(System.getProperty("user.dir") + File.separator + "testAnimePicCache.bin");
- ObjectOutputStream oos = new ObjectOutputStream(out);
- oos.writeObject(EventListener.testAnimePicCache);
- oos.flush();
- oos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }, 1, 5, TimeUnit.MINUTES);*/
- // DEPRECATED //or is it? make unmodifiable instead
+ //DEPRECATED //or is it? make unmodifiable instead
for(String id : tokens.getProperty("botmod").split(",")) {
ModID.add(id);
}
ModID.add(OwnerID);
+
+ //TODO put into sql and make guild setting to opt out
logExcemptID.add(BotID);
}
private static void initDB() { //init guild settings when do !desp settings for the first time? //dont really need coz im doing upsert for all values anyways
HikariConfig dbConf = new HikariConfig();
dbConf.setJdbcUrl("jdbc:sqlite:data.db");
dbConf.setIdleTimeout(45000);
dbConf.setMaxLifetime(60000);
dbConf.setMaximumPoolSize(10);
//dbConf.setMaximumPoolSize(25); //for deployment in server
db = new HikariDataSource(dbConf);
try (Connection con = db.getConnection()){
Statement s = con.createStatement();
s.execute("CREATE TABLE IF NOT EXISTS settings"
+ "(id INTEGER PRIMARY KEY," //performance problem using text; integer can handle long anyways
+ "prefix TEXT DEFAULT '!desp ',"
+ "premium INTEGER DEFAULT 0,"
+ "mchannel TEXT," //allow people to set this manually? By default, use last music cmd place
+ "locale TEXT DEFAULT 'EN'," //or int? //user specific or guild specific, or user override guild?
+ "shortcuts TEXT," //use another method?
+ "votepct INTEGER DEFAULT 50,"
+ "looplimit INTEGER DEFAULT 1,"
+ "volume INTEGER DEFAULT 100," //premium?, is default actually 100?
+ "helpdm INTEGER DEFAULT 0);"); //send help to dm or not, excluding cmd help(?)
//add logexempt?
+
+ //init perms table
PreparedStatement pragma = con.prepareStatement("SELECT name FROM pragma_table_info('perms_' || ?);"); //NOTE: sqlite does not support changing default values, beware when adding new commands
for(Entry<String, List<Command>> entry : catCmds.entrySet()) {
pragma.setString(1, entry.getKey().toLowerCase());
ResultSet rs = pragma.executeQuery();
+
+ //traverse cmd tree to obtain node names
boolean isEmpty = true;
HashMap<String, EnumSet<Permission>> nodes = new HashMap<>();
Stack<Command> tree = new Stack<>();
for(Command cmd : entry.getValue()) tree.push(cmd); //populate stack coz there is no root node
while(!tree.empty()) {
Command cmd = tree.pop();
String name = cmd.getName();
for(Command iterate = cmd.getParent(); iterate != null; iterate = iterate.getParent()) {
name = iterate.getName() + "." + name;
}
nodes.put(name, cmd.getDefaultPerms());
for(String sub : cmd.getSubCommandNames()) {
tree.push(cmd.getSubCommand(sub));
}
}
while(rs.next()) {
isEmpty = false;
nodes.remove(rs.getString("name")); //remove already added node names
}
if(isEmpty) {
String create = "CREATE TABLE perms_" + entry.getKey().toLowerCase() + " (id INTEGER PRIMARY KEY, _GLOBAL_ TEXT DEFAULT '0\n', "; //perms for a category are always default no restraints
StringJoiner join = new StringJoiner(", ");
for(Entry<String, EnumSet<Permission>> node : nodes.entrySet()) {
join.add("\"" + node.getKey() + "\" TEXT DEFAULT '" + ((0L << 32) | (Permission.getRaw(node.getValue()) & 0xffffffffL)) + "\n'"); //initialize with no permission deny override, permissions allow //needs to be text so that channel overrides delimiter can be stored
}
create += join.toString() + ");";
s.execute(create);
//DONE? create table
} else {
if(!nodes.isEmpty()) { //which means there is new subCmd/cmd
for(Entry<String, EnumSet<Permission>> node : nodes.entrySet()) {
s.execute("ALTER TABLE perms_" + entry.getKey().toLowerCase() + " ADD COLUMN \"" + node.getKey() + "\" TEXT DEFAULT '" + ((0L << 32) | (Permission.getRaw(node.getValue()) & 0xffffffffL)) + "\n';"); //not able to prep statement coz its column name
s.close();
}
}
}
}
pragma.close();
+
+ //init users table
+
//DONE TEST generate the nodes, retrieve default from fields? //what about additional commands added, use ALTER TABLE ADD COLUMN DEFAULT? I dont need to sort it according to category at all, i am not and will not be bulk printing permissions anywhere //actually i might be coz of list edited perms
//fit subnodes into sub tables, split by category so its more balanced (category as table name)?
//fields are gonna be sth like <channelid>:<perm>|<perm> etc?
//DONE store the permissions with long merged; <32bit = deny, >32bit = allow
s.execute("CREATE TABLE IF NOT EXISTS users"
+ "(id INTEGER PRIMARY KEY,"
+ "reports TEXT DEFAULT '',"
+ "game TEXT);"); //disposable, i can change it anytime
//add botmod field? if so, i can deprecate the hard coded list, but it would require querying to this table on perm checks //i need to query it to check if the user is banned anyways //subcmd need to query again, so i didnt do it; besides the modlist is gonna be too small to be significant anyways
//add user specific locale? might be confusing
s.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
private static void initCmds() {
Reflections reflections = new Reflections("me.despawningbone.discordbot.command");
Set<Class<? extends Command>> classes = reflections.getSubTypesOf(Command.class);
for (Class<? extends Command> s : classes) {
try {
+ //skip abstract classes
if (Modifier.isAbstract(s.getModifiers())) {
continue;
}
+
String pkName = s.getPackage().getName();
String cat = StringUtils.capitalize(pkName.substring(pkName.lastIndexOf(".") + 1));
- //if(cat.equals("Osu")) cat = "osu!";
Command c = s.getConstructor().newInstance(); //DONE use constructor to put name and cat instead
+ //dont skip disabled commands - they should still show up but disabled
- if (c.isDisabled()) {
- continue;
- }
- try { //init name and cat
+ //init name and cat
+ try {
Field nameF = Command.class.getDeclaredField("name");
nameF.setAccessible(true);
if(nameF.get(c) == null) nameF.set(c, s.getSimpleName().toLowerCase()); //allow overrides
Field catF = Command.class.getDeclaredField("cat");
catF.setAccessible(true);
catF.set(c, cat);
} catch (NoSuchFieldException e) { //should never throw
e.printStackTrace();
}
- // check disable whole command category?
+
+ //check disable whole command category? //no non-perm-wise category wide disabling support
List<Command> cmds = catCmds.get(cat);
if(cmds == null) {
cmds = new ArrayList<Command>(Arrays.asList(c));
} else {
cmds.add(c);
}
catCmds.put(cat, cmds);
- // set command category?
commands.put(c.getName(), c);
List<String> l = c.getAliases();
if(l != null) {
for(int i = 0; i < l.size(); i++) {
aliases.put(l.get(i), c);
}
}
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}
+
+ //sort each category alphabetically
for(Entry<String, List<Command>> entry : catCmds.entrySet()) {
Collections.sort(entry.getValue(), (a, b) -> a.getName().compareTo(b.getName()));
}
}
}
diff --git a/src/me/despawningbone/discordbot/EventListener.java b/src/me/despawningbone/discordbot/EventListener.java
index 657e613..1fa64eb 100644
--- a/src/me/despawningbone/discordbot/EventListener.java
+++ b/src/me/despawningbone/discordbot/EventListener.java
@@ -1,419 +1,314 @@
package me.despawningbone.discordbot;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Element;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import me.despawningbone.discordbot.command.music.AudioTrackHandler;
import me.despawningbone.discordbot.command.music.GuildMusicManager;
import me.despawningbone.discordbot.command.music.Music;
import me.despawningbone.discordbot.utils.MiscUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildVoiceState;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.entities.Message.Attachment;
-import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
import net.dv8tion.jda.api.events.user.UserActivityStartEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class EventListener extends ListenerAdapter {
- public static Multimap<String, String> testAnimePicCache = ArrayListMultimap.create();
-
@Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
DiscordBot.mainJDA = event.getJDA(); // refresh it? //no need, everything's getJDA() is the same jda basis but audioplayer's still using it; need to migrate to store in guildmusicmanager
- //String[] words = event.getMessage().getContentDisplay().split(" ");
User author = event.getAuthor();
TextChannel channel = event.getChannel();
Message msg = event.getMessage();
-
- //checkAnimePics(event);
//DONE use log4j
//logging
if (!DiscordBot.logExcemptID.contains(author.getId())) {
String guildinfo = "[" + event.getGuild().getName() + " #" + channel.getName() + "]";
String payload = "[INFO] " + guildinfo + System.lineSeparator() + " " + msg + System.lineSeparator() + " Full msg: " + msg.getContentDisplay();
List<Attachment> att = event.getMessage().getAttachments();
if (!att.isEmpty()) {
payload += System.lineSeparator() + " Attachments:";
for (int i = 0; i < att.size(); i++) {
payload += System.lineSeparator() + " " + att.get(i).getUrl();
}
}
DiscordBot.logger.trace(payload); //TODO log embeds and add user id too?
}
- /*if (String.join("", words).equalsIgnoreCase("!despacito")) {
- channel.sendMessage("https://www.youtube.com/watch?v=W3GrSMYbkBE").queue();
- return;
- }*/
+ //parse cmd
CommandResult result = null;
-
try (Connection con = DiscordBot.db.getConnection(); Statement s = con.createStatement()){
+ //check prefix
String prefix = MiscUtils.getPrefix(s, event.getGuild().getId());
if(msg.getContentDisplay().toLowerCase().startsWith(prefix.toLowerCase())) {
+ //preprocess args
String msgStripped = msg.getContentDisplay().substring(prefix.length()).replaceAll("\\s\\s+", " "); //merges space
String[] args = msgStripped.split(" "); // base on command length?
+
+ //get cmd from args
Command cmd = DiscordBot.commands.get(args[0].toLowerCase());
cmd = cmd == null ? DiscordBot.aliases.get(args[0].toLowerCase()) : cmd;
if (cmd != null) {
+
+ //check if banned
ResultSet uRs = s.executeQuery("SELECT reports FROM users WHERE id = " + author.getId() + ";");
if(uRs.next()) { //checks null at the same time
if(uRs.getString(1).split("\n").length >= 5) {
channel.sendMessage("You are banned from using the bot.").queue();
DiscordBot.logger.info("[WARN] " + author.getName() + " (" + author.getId() + ") tried to execute " + msg.getContentDisplay() + " but was banned.");
return;
}
}
uRs.close();
+
+ //check perms
long perm = MiscUtils.getActivePerms(s, channel, cmd);
- //result = cmd.execute(channel, author, msg, args);
String perms = cmd.hasSubCommand() ? null : MiscUtils.getMissingPerms(perm, cmd.getRequiredBotUserLevel(), event.getMember(), channel); //pass it to the subcommand handler to handle instead
if(cmd.isDisabled()) perms = "DISABLED"; //override if disabled by code
+
if(perms == null || event.getAuthor().getId().equals(DiscordBot.OwnerID)) { //owner overrides perms for convenience
- /*if(cmd.isDisabled(channel.getGuild().getId())) {
- channel.sendMessage("This command is disabled!").queue();
- result = new CommandResult(CommandResultType.FAILURE, "Disabled command");
- } else {*/
- cmd.executeAsync(channel, author, msg, Arrays.copyOfRange(args, 1, args.length), r -> { //catch all exceptions? //should have actually
- DiscordBot.logger.info("[" + r.getResultType() + "] " + author.getName() + " (" + author.getId() + ") executed "
- + msg.getContentDisplay() + (r.getRemarks() == null ? "." : ". (" + r.getRemarks() + ")")); //logging has to be before sendMessage, or else if no permission it will just quit
- if(r.getMessage() != null) channel.sendMessage(r.getMessage()).queue();
- }); //dont know if async will screw anything up //wont, TODO log date and which server executed the command also?
- return;
- //}
+
+ //execute async
+ cmd.executeAsync(channel, author, msg, Arrays.copyOfRange(args, 1, args.length), r -> { //catch all exceptions? //should have actually
+ DiscordBot.logger.info("[" + r.getResultType() + "] " + author.getName() + " (" + author.getId() + ") executed "
+ + msg.getContentDisplay() + (r.getRemarks() == null ? "." : ". (" + r.getRemarks() + ")")); //logging has to be before sendMessage, or else if no permission it will just quit
+ if(r.getMessage() != null) channel.sendMessage(r.getMessage()).queue();
+ }); //dont know if async will screw anything up //wont, TODO log date and which server executed the command also?
+ return;
+
} else if(perms.equals("DISABLED")) {
author.openPrivateChannel().queue(c -> //notify user whats wrong if possible
c.sendMessage("Sorry, but the command `" + msg.getContentDisplay() + "` is disabled in the channel `#" + channel.getName() + "`.").queue());
- msg.addReaction("❎").queue();
+ msg.addReaction("❎").queue(); //instead of sending messages, react instead to avoid clutter (which is what most ppl disable a bot in a channel for)
result = new CommandResult(CommandResultType.DISABLED);
} else {
result = new CommandResult(CommandResultType.NOPERMS, perms);
channel.sendMessage(result.getMessage()).queue();
}
} else {
result = new CommandResult(CommandResultType.FAILURE, "Invalid command");
//do more stuff?
}
- } else if(msg.getContentRaw().matches("<@!?" + DiscordBot.BotID + ">")) result = greet(channel, author, prefix);
+
+ //non prefix "command" - greetings with tagging
+ } else if(msg.getContentRaw().matches("<@!?" + DiscordBot.BotID + ">")) {
+ result = greet(channel, author, prefix);
+ }
} catch (SQLException e) {
result = new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
+
+ //log non async results
if(result != null) DiscordBot.logger.info("[" + result.getResultType() + "] " + author.getName() + " (" + author.getId() + ") executed "
+ msg.getContentDisplay() + (result.getRemarks() == null ? "." : ". (" + result.getRemarks() + ")"));
}
- @SuppressWarnings("unused")
- private void checkAnimePics(GuildMessageReceivedEvent event) {
- //TESTING
- CompletableFuture.runAsync(() -> {
- User author = event.getAuthor();
- TextChannel channel = event.getChannel();
- Message msg = event.getMessage();
- List<String> pics = new ArrayList<>();
- if(channel.getId().equals("615396635383562272") && !DiscordBot.BotID.equals(author.getId())) {
- for(Attachment att : msg.getAttachments()) {
- if(att.isImage()) pics.add(att.getUrl());
- }
- /*if(msg.getContentDisplay().contains("http")) {
- for(String s : msg.getContentDisplay().split("http")) {
- try {
- new URL("http" + s);
- pics.add("http" + s);
- } catch(MalformedURLException e) {
- ;
- }
- }
- }*/
- try {
- Thread.sleep(1500);
- msg = channel.retrieveMessageById(msg.getId()).complete();
- } catch (InterruptedException e2) {
- e2.printStackTrace();
- }
- for(MessageEmbed em : msg.getEmbeds()) {
- //System.out.println(em.toJSONObject());
- if(em.getThumbnail() != null) {
- System.out.println("thumb");
- if(em.getSiteProvider() != null && em.getSiteProvider().getName().equals("pixiv")) { //pixiv doesnt show whole pic in embed
- pics.add(em.getUrl());
- } else {
- pics.add(em.getThumbnail().getUrl());
- }
- } else if(em.getImage() != null && !author.isBot()) {
- System.out.println("img");
- pics.add(em.getImage().getUrl());
- } else {
- System.out.println("url");
- pics.add(em.getUrl());
- }
-
- }
- //System.out.println(pics);
- //System.out.println(testAnimePicCache);
- for(String pic : pics) { //handle first since these mustnt be the same urls, therefore cache saucenao sauce instead
- String origPic = pic;
- if(!testAnimePicCache.containsValue(pic)) {
- Element saucenao;
- try {
- saucenao = Jsoup.connect("https://saucenao.com/search.php?url=" + pic).get().body();
- Element result = saucenao.selectFirst(".resulttable");
- try { //normal pixiv/deviantart handling
- if(result.parent().attr("class").equals("result hidden")) throw new NullPointerException();
- Element source = result.selectFirst("strong:contains(ID:)").nextElementSibling();
- pic = source.attr("href"); //will not run if the cache has the value || if the link specified aint a pic
- } catch (NullPointerException e1) { //weird saucenao card formatting (eg episode info), or no result; we dont handle these
- ;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- System.out.println("next" + testAnimePicCache);
- if(testAnimePicCache.containsValue(pic)) {
- try {
- Multimap<String, String> temp = ArrayListMultimap.create();
- System.out.println("temp");
- Message m = channel.retrieveMessageById(Multimaps.invertFrom(testAnimePicCache, temp).get(pic).toArray(new String[1])[0]).complete();
- EmbedBuilder eb = new EmbedBuilder();
- eb.setTitle("Repost detected!");
- eb.setDescription("[This image](" + origPic + ")" + (origPic.equals(pic) ? "" : "([source](" + pic + "))") + " is a repost of [this message](" + m.getJumpUrl() + ") by `" + m.getAuthor().getName() + "#" + m.getAuthor().getDiscriminator() + "` at **" + m.getTimeCreated().format(DateTimeFormatter.RFC_1123_DATE_TIME) + "**.\n");
- eb.setThumbnail(origPic);
- channel.sendMessage(eb.build()).queue();
- continue;
- } catch(NullPointerException e) { //if the message is deleted
- e.printStackTrace();
- }
- } else {
- System.out.println("put");
- testAnimePicCache.put(msg.getId(), pic);
- }
-
- }
- }
- }).whenComplete((r, t) -> {if(t != null) t.printStackTrace();});
- }
+ //init easter eggs file
private Properties greetEasterEggs = new Properties();
{
try(FileInputStream in = new FileInputStream(new File(System.getProperty("user.dir") + File.separator + "eastereggs.properties"))){
greetEasterEggs.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
private CommandResult greet(TextChannel channel, User author, String prefix) {
MessageBuilder smsg = new MessageBuilder();
+
+ //main greet
String nick = channel.getGuild().getMemberById(author.getId()).getNickname();
if (nick != null) {
smsg.append("Yo " + nick + "!\n");
} else {
smsg.append("Yo " + author.getName() + "!\n");
}
+
+ //easter eggs
String easterEgg = greetEasterEggs.getProperty(author.getId());
if(easterEgg != null) {
smsg.append(easterEgg.replace("\\n", "\n") + "\n");
}
+
+ //bot info
EmbedBuilder eb = new EmbedBuilder();
eb.setColor(0x051153); //TODO version info based on git commits
eb.appendDescription("This bot is running **despbot v1.5.0**, Shard `" + DiscordBot.mainJDA.getShardInfo().getShardString() + "`. ([invite me!](https://discordapp.com/oauth2/authorize?&client_id=" + DiscordBot.BotID + "&scope=bot&permissions=0))\n");
eb.appendDescription("Connected guilds: `" + DiscordBot.mainJDA.getGuildCache().size() + (DiscordBot.mainJDA.getShardManager() == null ? "" : "/" + DiscordBot.mainJDA.getShardManager().getShards().stream().mapToLong(jda -> jda.getGuildCache().size()).sum()) + "`; ");
eb.appendDescription("Total members (cached): `" + DiscordBot.mainJDA.getUserCache().size() + (DiscordBot.mainJDA.getShardManager() == null ? "" : "/" + DiscordBot.mainJDA.getShardManager().getShards().stream().mapToLong(jda -> jda.getUserCache().size()).sum()) + "`\n");
eb.appendDescription("DM `" + DiscordBot.mainJDA.getUserById(DiscordBot.OwnerID).getAsTag() + "` if you have any questions!\n");
eb.appendDescription("To get a list of commands, do `" + prefix + "help`.");
smsg.setEmbed(eb.build());
Message fmsg = smsg.build();
channel.sendMessage(fmsg).queue();
return new CommandResult(CommandResultType.SUCCESS, null);
}
+
@Override
- public void onGuildMessageUpdate(GuildMessageUpdateEvent event) {
- //System.out.println("edit"); //debug
+ public void onGuildMessageUpdate(GuildMessageUpdateEvent event) { //log edits
Message msg = event.getMessage();
User author = event.getAuthor();
TextChannel channel = event.getChannel();
if (!DiscordBot.logExcemptID.contains(author.getId())) {
String guildinfo = "[" + event.getGuild().getName() + " #" + channel.getName() + "]";
DiscordBot.logger.trace("[EDIT] " + guildinfo + System.lineSeparator() + " " + msg + System.lineSeparator() + " Full edited msg: " + msg.getContentDisplay());
}
}
@Override
public void onUserActivityStart(UserActivityStartEvent event) { //store presence for checking osu pp
Activity osu = event.getNewActivity();
if (osu != null && osu.getName().equals("osu!") && osu.isRich() //if need to include other games and details, just remove this if clause and change sGame below
&& osu.asRichPresence().getDetails() != null) {
String toolTip = osu.asRichPresence().getLargeImage().getText();
- //DiscordBot.guildMemberPresence.put(event.getUser().getId(), game); //so that game update to nothing wont be logged
- /*System.out.println(event.getGuild().getName());
- System.out.println(event.getUser().getName());
- System.out.println(game.getName());
- System.out.println(game.getUrl());
- System.out.println(game.getType());
- System.out.println(game.isRich() ? game.asRichPresence().getDetails() : "no rich");
- System.out.println(game.isRich() ? game.asRichPresence().getState() : "no rich");*/
- //OffsetDateTime timesent = OffsetDateTime.now();
- //System.out.println(toolTip);
String sGame = (toolTip.lastIndexOf(" (") != -1 ? toolTip.substring(0, toolTip.lastIndexOf(" (")) : toolTip) + "||" + osu.asRichPresence().getDetails();
- //sGame = sGame.replaceAll("'", "''");
- /*OffsetDateTime timeReceived = OffsetDateTime.now();
- long ms = Math.abs(timesent.until(timeReceived, ChronoUnit.MILLIS));
- System.out.println("Time taken: " + ms + "ms");*/
+
+ //update db
try (Connection con = DiscordBot.db.getConnection()) { //DONE do i need to close the statement?
PreparedStatement s = con.prepareStatement("INSERT INTO users(id, game) VALUES (" + event.getUser().getId() + ", ?) ON CONFLICT(id) DO UPDATE SET game = ? WHERE game <> ?;" ); //prevent blank updates
s.setString(1, sGame); s.setString(2, sGame); s.setString(3, sGame);
s.execute();
- //con.createStatement().execute("INSERT INTO users(id, game) VALUES (" + event.getUser().getId() + ", '" + sGame + "') ON CONFLICT(id) DO UPDATE SET game = '" + sGame + "' WHERE game <> '" + sGame + "';" ); //prevent blank updates
} catch (SQLException e) { //FIXED if i make this not osu only, be aware of SQL injections through sGame (probably being paranoid tho)
e.printStackTrace();
}
- /*timeReceived = OffsetDateTime.now();
- ms = Math.abs(timesent.until(timeReceived, ChronoUnit.MILLIS));
- System.out.println("Time taken: " + ms + "ms");*/
}
}
+
//TODO only update when not paused?
//TODO update on member deafen?
private void waitActivity(Guild guild) {
AudioTrackHandler ap = ((Music) DiscordBot.commands.get("music")).getAudioTrackHandler();
ap.getGuildMusicManager(guild).player.setPaused(true);
ap.getGuildMusicManager(guild).clearQueueCleanup = ap.ex.schedule(() -> {
ap.stopAndClearQueue(guild);
DiscordBot.lastMusicCmd.get(guild.getId()).sendMessage("The queue has been cleared.").queue();
ap.getGuildMusicManager(guild).clearQueueCleanup = null;
}, 1, TimeUnit.MINUTES);
}
private String updateActivity(Guild guild, VoiceChannel vc) {
AudioTrackHandler ap = ((Music) DiscordBot.commands.get("music")).getAudioTrackHandler();
GuildMusicManager mm = ap.getGuildMusicManager(guild);
if(mm.clearQueueCleanup != null) {
mm.player.setPaused(false);
mm.clearQueueCleanup.cancel(true);
mm.clearQueueCleanup = null;
}
String type = mm.scheduler.loop; //mm cannot be null
if (type != null
&& vc.getMembers().size() > 2
&& vc.getMembers().contains(guild.getMemberById(DiscordBot.OwnerID))) {
ap.toggleLoopQueue(guild, type);
return type;
}
return null;
}
@Override
public void onGuildVoiceLeave(GuildVoiceLeaveEvent event) { // theoretically i dont need to check if lastMusicCmd has the entry or not, as it must have one to trigger this
GuildVoiceState vs = event.getGuild().getMemberById(DiscordBot.BotID).getVoiceState();
if(!event.getMember().getUser().getId().equals(DiscordBot.BotID)) {
if (vs.inVoiceChannel()) {
if (vs.getChannel().equals(event.getChannelLeft())
&& event.getChannelLeft().getMembers().size() < 2) {
TextChannel channel = DiscordBot.lastMusicCmd.get(event.getGuild().getId());
channel.sendMessage(
"All users have left the music channel, the player is now paused.\nThe queue will be cleared in 1 minute if there is no activity.")
.queue();
waitActivity(event.getGuild());
}
}
} else { //got kicked
AudioTrackHandler ap = ((Music) DiscordBot.commands.get("music")).getAudioTrackHandler();
if(ap != null) { //if not destroyed
ap.stopAndClearQueue(event.getGuild()); //can double fire on normal end; shouldnt be too big of a problem
}
}
}
@Override
public void onGuildVoiceMove(GuildVoiceMoveEvent event) { // theoretically i dont need to check if lastMusicCmd has the entry or not, as it must have one to trigger this
GuildVoiceState vs = event.getGuild().getMemberById(DiscordBot.BotID).getVoiceState();
if (vs.inVoiceChannel()) {
String id = event.getGuild().getId();
TextChannel channel = DiscordBot.lastMusicCmd.get(id);
if (!event.getMember().getUser().getId().equals(DiscordBot.BotID)) {
if (vs.getChannel().equals(event.getChannelLeft())) {
if (!event.getMember().getUser().getId().equals(DiscordBot.BotID)
&& event.getChannelLeft().getMembers().size() < 2) {
channel.sendMessage(
"All users have left the music channel, the player is now paused.\nThe queue will be cleared in 1 minute if there is no activity.")
.queue();
waitActivity(event.getGuild());
}
} else if (vs.getChannel().equals(event.getChannelJoined())) {
String type = updateActivity(event.getGuild(), event.getChannelJoined());
if(type != null) channel.sendMessage((type.equals("loop") ? "Looping" : "Autoplay") + " mode disabled due to new users joining the music channel.").queue();
}
} else { //moved bot to empty channel
if(event.getChannelJoined().getMembers().size() < 2) {
channel.sendMessage(
"The bot has been moved to an empty channel, the player is now paused.\nThe queue will be cleared in 1 minute if there is no activity.")
.queue();
waitActivity(event.getGuild());
} else { //moved bot to channel with ppl
event.getGuild().getAudioManager().openAudioConnection(event.getChannelJoined()); //seems to need explicit reconnect on bot move, it gets stuck on attempting to reconnect otherwise; probably would be fixed soon but hot patch for now
String type = updateActivity(event.getGuild(), event.getChannelJoined());
if(type != null) channel.sendMessage((type.equals("loop") ? "Looping" : "Autoplay") + " mode disabled due to new users joining the music channel.").queue();
}
}
}
}
@Override
public void onGuildVoiceJoin(GuildVoiceJoinEvent event) {
GuildVoiceState vs = event.getGuild().getMemberById(DiscordBot.BotID).getVoiceState();
String id = event.getGuild().getId();
TextChannel channel = DiscordBot.lastMusicCmd.get(id);
if(channel != null) {
if (vs.inVoiceChannel() && !event.getMember().getUser().getId().equals(DiscordBot.BotID)) {
if (vs.getChannel().equals(event.getChannelJoined())) {
String type = updateActivity(event.getGuild(), event.getChannelJoined());
if(type != null) channel.sendMessage((type.equals("loop") ? "Looping" : "Autoplay") + " mode disabled due to new users joining the music channel.").queue();
}
}
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/Command.java b/src/me/despawningbone/discordbot/command/Command.java
index ec581fd..5c3ba94 100644
--- a/src/me/despawningbone/discordbot/command/Command.java
+++ b/src/me/despawningbone/discordbot/command/Command.java
@@ -1,212 +1,214 @@
package me.despawningbone.discordbot.command;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
//import java.time.OffsetDateTime;
//import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import org.apache.commons.lang3.exception.ExceptionUtils;
import me.despawningbone.discordbot.DiscordBot;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import me.despawningbone.discordbot.utils.MiscUtils;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class Command { //no need to be abstract anymore //make it final to ensure thread safety?
protected String name;
protected String desc;
protected String usage;
protected List<String> alias; //fixed-size in this case is negligible, as it will not be edited later on anyways
protected List<String> remarks = null;
protected boolean isDisabled;
protected EnumSet<Permission> perms = EnumSet.noneOf(Permission.class); //so that not configured commands would have a default of no perms needed, instead of null //WILL NOT ALLOW DENY OVERRIDE FOR NOW
protected int botUserLevel; //0 = everyone, 1 = BotMod, 2 = BotOwner; negative value = either BotUser or required perm
protected List<String> examples;
protected ExecuteImpl impl = null;
private Command parent = null;
private String cat; //not used; remove? //actually gets used now
private LinkedHashMap<String, Command> subCmds = new LinkedHashMap<>(); //preserve order
public HashMap<String, Command> subCmdAliases = new HashMap<String, Command>(); //TODO temporary solution
//DONE add examples; what about subcmds?
//for overriding
protected Command() {}
//only used by nested commands, since all explicitly declared commands override execute(); hot creation of subcommands are possible, but permission setting via !desp settings is not supported
public Command(String name, List<String> aliases, Command.ExecuteImpl exeFunc, String usage, List<String> examples, String desc, List<String> remarks, EnumSet<Permission> defaultPerms, int botUserLevel) {
this.name = name;
this.alias = aliases;
this.impl = exeFunc;
this.usage = usage;
this.examples = examples;
this.desc = desc;
this.remarks = remarks;
this.perms = defaultPerms;
this.botUserLevel = botUserLevel;
}
public interface ExecuteImpl { //DONE make this a seperate class to store the ever increasing params? if so, protected constructor since it doesnt need to be instantiated elsewhere other than registerSubCommand here //implemented nested commands instead
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args);
}
private void setParent(Command parent) { //private so only register function can access to avoid accidental use
this.parent = parent;
}
//for anonymous inner classes if needed
public void registerSubCommand(Command subCmd) {
subCmd.setParent(this); //make parent only set on register since subcmds with wrong/no parents can result in finnicky bugs
subCmds.put(subCmd.getName(), subCmd);
if(subCmd.getAliases() != null) subCmd.getAliases().forEach(a -> subCmdAliases.put(a, subCmd));
}
public void registerSubCommand(String name, List<String> aliases, Command.ExecuteImpl exe, String usage, List<String> examples, String desc, List<String> remarks) { //subcmd has its own examples? //DONE subcmd permissions and botuserlevel //probably not needed, as its gonna be binded to guild instead of cmds soon enough
registerSubCommand(name, aliases, exe, usage, examples, desc, remarks, EnumSet.noneOf(Permission.class), 0);
}
public void registerSubCommand(String name, List<String> aliases, Command.ExecuteImpl exe, String usage, List<String> examples, String desc, List<String> remarks, EnumSet<Permission> defaultPerms, int botUserLevel) {
Command subCmd = new Command(name, aliases, exe, usage, examples, desc, remarks, defaultPerms, botUserLevel);
registerSubCommand(subCmd);
}
public boolean hasSubCommand() {
return !subCmds.isEmpty();
}
public Set<String> getSubCommandNames() {
return subCmds.keySet();
}
public Command getSubCommand(String name) {
Command subCmd = subCmds.get(name);
return subCmd == null ? subCmdAliases.get(name) : subCmd;
}
public Command getParent() {
return parent;
}
public enum BotUserLevel { //DONE? implement this DONE test this
DEFAULT,
BOT_MOD,
BOT_OWNER
}
public String getCategory() { //is null if it is a subcommand
return cat;
}
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
public String getUsage() {
return usage;
}
public List<String> getAliases() {
return alias;
}
public List<String> getRemarks() {
return remarks;
}
public EnumSet<Permission> getDefaultPerms() { //DONE make this channel dependent?
return perms;
}
public int getRequiredBotUserLevel() {
return botUserLevel;
}
public List<String> getExamples() {
return examples;
}
public boolean isDisabled() { //FIXED think of what to do with disabledGuild; it makes the command class not thread safe; store in DB instead, and be channel based?
return isDisabled;
}
+ //TODO deprecate use of @Override execute, use Command.ExecuteImpl instead - this allows merging of perm handlers in EventListener and here
+
//even when multiple thread references to one specific command, it should be thread safe because it doesnt modify anything in the execute stage; and even the hashmap is somewhat immutable as it will never be changed after finished loading
//i dont think i need to even volatile that hashmap
//the only thing i might need to do to make it thread safe is to make the hashmap a concurrenthashmap
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) { //if you want a main command to work with sub commands, just define impl along with subcmds instead of overriding this method
OffsetDateTime timesent = OffsetDateTime.now();
try(Connection con = DiscordBot.db.getConnection(); Statement s = con.createStatement()) { //not the best, but i cant share connection through threads
String prefix = MiscUtils.getPrefix(s, channel.getGuild().getId());
if(hasSubCommand()) {
if(args.length > 0) {
Command subCmd = getSubCommand(args[0].toLowerCase());
if(subCmd != null) {
int botUserLevel = subCmd.getRequiredBotUserLevel(); Command temp = subCmd;
while(temp.getParent() != null && botUserLevel == 0) {
temp = temp.getParent();
botUserLevel = temp.getRequiredBotUserLevel(); //if not set get parent's
}
-
+
String perms = subCmd.hasSubCommand() ? null : MiscUtils.getMissingPerms(MiscUtils.getActivePerms(s, channel, subCmd), botUserLevel, channel.getGuild().getMember(author), channel); //yet again pass to handler
if(subCmd.isDisabled()) perms = "DISABLED"; //override if disabled by code
-
+
if(perms == null || author.getId().equals(DiscordBot.OwnerID)) { //owner overrides perms for convenience
OffsetDateTime timeReceived = OffsetDateTime.now();
long ms = Math.abs(timesent.until(timeReceived, ChronoUnit.MILLIS));
System.out.println("subcmd parse Time taken: " + ms + "ms");
return subCmd.execute(channel, author, msg, Arrays.copyOfRange(args, 1, args.length));
} else if(perms.equals("DISABLED")) {
author.openPrivateChannel().queue(c -> //notify user whats wrong if possible
c.sendMessage("Sorry, but the command `" + msg.getContentDisplay() + "` is disabled in the channel `#" + channel.getName() + "`.").queue());
msg.addReaction("❎").queue();
return new CommandResult(CommandResultType.DISABLED);
} else {
return new CommandResult(CommandResultType.NOPERMS, perms);
}
-
+
} else {
if(impl == null) return new CommandResult(CommandResultType.INVALIDARGS, "Unknown sub command! Check `" + prefix + "help " + this.getName() + "` for more info.");
}
} else { //only run if no execute definition, if not let it override default messages
if(impl == null) return new CommandResult(CommandResultType.INVALIDARGS, "Please specify a subcommand. You can view them with `" + prefix + "help " + this.name + "`.");
}
}
return impl.execute(channel, author, msg, args); //fallback if no subcommand found; useful for defining custom messages or default command for a set of subcommands
} catch (SQLException e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
}
public void executeAsync(TextChannel channel, User author, Message msg, String[] args, Consumer<CommandResult> success) {
OffsetDateTime timesent = OffsetDateTime.now();
CompletableFuture.supplyAsync(() -> execute(channel, author, msg, args))
.exceptionally(ex -> new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(ex.getCause()))) //getCause should always work as ex is a CompletionException
.thenAccept(success).thenAccept(r -> { //DONE thenAccept parses the CommandResult
OffsetDateTime timeReceived = OffsetDateTime.now();
long ms = Math.abs(timesent.until(timeReceived, ChronoUnit.MILLIS));
System.out.println("Time taken: " + ms + "ms");
});
}
}
diff --git a/src/me/despawningbone/discordbot/command/admin/BotBan.java b/src/me/despawningbone/discordbot/command/admin/BotBan.java
index c9349f4..d9f29a8 100644
--- a/src/me/despawningbone/discordbot/command/admin/BotBan.java
+++ b/src/me/despawningbone/discordbot/command/admin/BotBan.java
@@ -1,118 +1,76 @@
package me.despawningbone.discordbot.command.admin;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import org.apache.commons.lang3.exception.ExceptionUtils;
import me.despawningbone.discordbot.DiscordBot;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class BotBan extends Command {
public BotBan() {
this.alias = Arrays.asList("bban");
this.desc = "Ban a user from the bot";
this.usage = "<userID>";
this.examples = Arrays.asList(DiscordBot.OwnerID);
this.botUserLevel = BotUserLevel.BOT_MOD.ordinal();
}
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
if (args.length < 1) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a user ID.");
} else {
- //boolean alrBanned = false;
String SID = args[0];
Member b;
try {
b = channel.getGuild().getMemberById(SID);
} catch (NumberFormatException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Invalid user ID.");
}
if (b != null) {
if (DiscordBot.ModID.contains(SID) || SID.equals(DiscordBot.BotID)) {
return new CommandResult(CommandResultType.FAILURE, "That user cannot be banned.");
} else {
try (Connection con = DiscordBot.db.getConnection(); Statement s = con.createStatement()) {
String reports = "";
ResultSet uRs = s.executeQuery("SELECT reports FROM users WHERE id = " + SID + ";");
+
if(uRs.next()) {
reports = uRs.getString(1);
if(reports.split("\n").length >= 5) {
return new CommandResult(CommandResultType.FAILURE, "The user is already banned from the bot.");
}
}
+
PreparedStatement set = con.prepareStatement("INSERT INTO users(id, reports) VALUES (?, \"0\n0\n0\n0\n0\n\") ON CONFLICT(id) DO UPDATE SET reports = \"0\n0\n0\n0\n0\n\"");
set.setString(1, SID);
+
if(set.executeUpdate() != 0) {
channel.sendMessage("You have successfully banned <@!" + SID + "> from the bot.").queue();
return new CommandResult(CommandResultType.SUCCESS);
} else {
- throw new IllegalArgumentException("This should never happen");
+ throw new IllegalStateException("This should never happen");
}
} catch (SQLException e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
-
- /*for (int i = 0; i < DiscordBot.BannedID.size(); i++) {
- if (DiscordBot.BannedID.get(i).equals(SID)) {
- alrBanned = true;
- break;
- }
- }
- if (!alrBanned) {
- boolean inList = false;
- for (int i = 0; i < DiscordBot.playerreportlist.size(); i++) {
- if (DiscordBot.playerreportlist.get(i).equals(SID)) {
- inList = true;
- DiscordBot.playerreportlist.set(i, SID + " " + "5");
- break;
- }
- }
- if (!inList) {
- DiscordBot.playerreportlist.add(SID + " " + "5");
- }
- DiscordBot.BannedID.add(SID);
- Path fp = Paths.get(System.getProperty("user.dir"), "PlayerReports.txt");
- try {
- List<String> fileContent = new ArrayList<>(
- Files.readAllLines(fp, StandardCharsets.UTF_8));
-
- for (int f = 0; f < fileContent.size(); f++) {
- if (fileContent.get(f).startsWith(SID)) {
- fileContent.set(f, SID + " " + "5");
- inList = true;
- break;
- }
- }
- if (!inList) {
- fileContent.add(SID + " " + "5");
- }
- Files.write(fp, fileContent, StandardCharsets.UTF_8);
- } catch (IOException e) {
- e.printStackTrace();
- }
- channel.sendMessage("You have successfully banned <@!" + SID + "> from the bot.").queue();
- return new CommandResult(CommandResultType.SUCCESS);
- } else {
- return new CommandResult(CommandResultType.FAILURE, "The user is already banned from the bot.");
- }*/
}
} else {
return new CommandResult(CommandResultType.FAILURE, "This user ID is invalid.");
}
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/admin/BotUnban.java b/src/me/despawningbone/discordbot/command/admin/BotUnban.java
index 091b99c..4786ed9 100644
--- a/src/me/despawningbone/discordbot/command/admin/BotUnban.java
+++ b/src/me/despawningbone/discordbot/command/admin/BotUnban.java
@@ -1,97 +1,64 @@
package me.despawningbone.discordbot.command.admin;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import org.apache.commons.lang3.exception.ExceptionUtils;
import me.despawningbone.discordbot.DiscordBot;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class BotUnban extends Command {
public BotUnban() {
this.alias = Arrays.asList("bunban");
this.desc = "Unban a user from the bot";
this.usage = "<userID>";
this.botUserLevel = BotUserLevel.BOT_MOD.ordinal();
this.examples = Arrays.asList(DiscordBot.OwnerID);
}
@Override //DONE rewrite BotBan/BotUnban to use SQLite
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
if (args.length < 1) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a user ID.");
} else {
- //boolean unbanned = false;
String SID = args[0];
Member t = channel.getGuild().getMemberById(SID);
if (t != null) {
try (Connection con = DiscordBot.db.getConnection(); Statement s = con.createStatement()) {
String reports = "";
ResultSet uRs = s.executeQuery("SELECT reports FROM users WHERE id = " + SID + ";");
if(uRs.next()) {
reports = uRs.getString(1);
if(reports.split("\n").length >= 5) {
//can actually just UPDATE since it must have an entry
PreparedStatement set = con.prepareStatement("INSERT INTO users(id, reports) VALUES (?, \"\") ON CONFLICT(id) DO UPDATE SET reports = \"\"");
set.setString(1, SID);
if(set.executeUpdate() != 0) {
channel.sendMessage("You unbanned <@!" + SID + ">.").queue();
return new CommandResult(CommandResultType.SUCCESS);
+ } else {
+ throw new IllegalStateException("This should never happen");
}
}
}
return new CommandResult(CommandResultType.FAILURE, "This user is not banned.");
} catch (SQLException e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
- /*for (int i = 0; i < DiscordBot.BannedID.size(); i++) {
- if (DiscordBot.BannedID.get(i).equals(SID)) {
- unbanned = true;
- DiscordBot.BannedID.remove(i);
- break;
- }
- }
- if (unbanned == true) {
- for (int i = 0; i < DiscordBot.playerreportlist.size(); i++) {
- if (DiscordBot.playerreportlist.get(i).startsWith(SID)) {
- DiscordBot.playerreportlist.remove(i);
- break;
- }
- }
- Path fp = Paths.get(System.getProperty("user.dir"), "PlayerReports.txt");
- try {
- List<String> fileContent = new ArrayList<>(Files.readAllLines(fp, StandardCharsets.UTF_8));
- for (int f = 0; f < fileContent.size(); f++) {
- if (fileContent.get(f).startsWith(SID)) {
- fileContent.remove(f);
- break;
- }
- }
- Files.write(fp, fileContent, StandardCharsets.UTF_8);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (unbanned == true) {
- channel.sendMessage("You unbanned <@!" + SID + ">.").queue();
- String name = channel.getGuild().getMemberById(SID).getEffectiveName();
- return new CommandResult(CommandResultType.SUCCESS, "User: " + name);
- }
- return new CommandResult(CommandResultType.FAILURE, "This user is not banned.");*/
} else {
return new CommandResult(CommandResultType.FAILURE, "This user ID is invalid.");
}
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/admin/Purge.java b/src/me/despawningbone/discordbot/command/admin/Purge.java
index 51ed140..60ea209 100644
--- a/src/me/despawningbone/discordbot/command/admin/Purge.java
+++ b/src/me/despawningbone/discordbot/command/admin/Purge.java
@@ -1,51 +1,53 @@
package me.despawningbone.discordbot.command.admin;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
import me.despawningbone.discordbot.DiscordBot;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class Purge extends Command {
public Purge() {
this.desc = "Clear the bot's message";
this.usage = "<count>";
this.remarks = Arrays.asList("Note: Count must be in between 1 to 100, and it includes the messages in between.");
this.botUserLevel = -BotUserLevel.BOT_MOD.ordinal();
this.examples = Arrays.asList("20");
this.perms = EnumSet.of(Permission.MESSAGE_MANAGE);
}
@Override //TODO rewrite purge to purge until message deleted meet the count instead
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
int n = 0;
try {
n = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a correct number.");
} catch (ArrayIndexOutOfBoundsException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a number.");
}
if (n > 100) {
return new CommandResult(CommandResultType.INVALIDARGS, "The number entered is too large.");
}
+
channel.getHistory().retrievePast(n).queue(history -> {
List<Message> msgs = history.stream()
.filter(hmsg -> hmsg.getAuthor().getId().equals(DiscordBot.BotID)).collect(Collectors.toList());
if(msgs.size() > 1 && channel.getGuild().getSelfMember().hasPermission(Permission.MESSAGE_MANAGE)) channel.deleteMessages(msgs).queue();
else msgs.forEach(m -> channel.deleteMessageById(m.getId()).queue());
//if no result ignore
});
+
return new CommandResult(CommandResultType.SUCCESS);
}
}
diff --git a/src/me/despawningbone/discordbot/command/admin/UserReport.java b/src/me/despawningbone/discordbot/command/admin/UserReport.java
index f9f846c..e6f0d39 100644
--- a/src/me/despawningbone/discordbot/command/admin/UserReport.java
+++ b/src/me/despawningbone/discordbot/command/admin/UserReport.java
@@ -1,183 +1,99 @@
package me.despawningbone.discordbot.command.admin;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.exception.ExceptionUtils;
import me.despawningbone.discordbot.DiscordBot;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class UserReport extends Command {
public UserReport() {
this.alias = Arrays.asList("ureport");
this.desc = "Report a user if they are abusing the bot!";
this.usage = "<userID/username>";
this.remarks = Arrays.asList("Note: 5 global reports will result in a ban from the bot.");
this.examples = Arrays.asList("311086271642599424", "despawningbone");
}
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
if (args.length < 1) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please specify which user you want to report.");
} else {
String SID = null;
boolean success = true;
String pname = String.join(" ", args);
long ID = 0;
try {
ID = Long.parseLong(pname);
} catch (NumberFormatException e) {
success = false;
// System.out.println(pname); //debug
List<Member> pm = channel.getGuild().getMembersByEffectiveName(pname, true);
if (pm.size() <= 0) {
return new CommandResult(CommandResultType.FAILURE, "There is no such user.");
} else if (pm.size() > 1) {
return new CommandResult(CommandResultType.FAILURE, "Theres more than 1 user with the same name. Please use !desp ID to get the ID of the user you want to report.");
} else {
SID = pm.get(0).getUser().getId();
ID = Long.parseLong(SID);
}
}
if (success == true) {
SID = Long.toString(ID);
}
if (author.getId().equals(SID)) {
return new CommandResult(CommandResultType.FAILURE, "You cannot report yourself you dumbo :stuck_out_tongue:");
} else if (DiscordBot.ModID.contains(SID) || SID.equals(DiscordBot.BotID)) {
return new CommandResult(CommandResultType.FAILURE, "That user cannot be reported.");
}
try (Connection con = DiscordBot.db.getConnection(); Statement s = con.createStatement()) {
String reports = "";
ResultSet uRs = s.executeQuery("SELECT reports FROM users WHERE id = " + SID + ";");
if(uRs.next()) {
reports = uRs.getString(1);
if(reports.contains(author.getId())) {
return new CommandResult(CommandResultType.FAILURE, "You cannot report a user more than once."); //make it so that its toggling the reports instead?
} else if(reports.split("\n").length < 5){
reports += author.getId() + "\n";
} else {
return new CommandResult(CommandResultType.FAILURE, "The user has already been banned!");
}
} else {
reports = author.getId() + "\n";
}
PreparedStatement set = con.prepareStatement("INSERT INTO users(id, reports) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET reports = ?" );
set.setString(1, SID);
set.setString(2, reports); set.setString(3, reports);
int update = set.executeUpdate();
if(update != 0) {
int times = reports.split("\n").length;
channel.sendMessage("You have successfully reported <@!" + ID + ">.\nThe user has been reported for "
+ times + "/5 times.\n").queue();
if(times >= 5) {
channel.sendMessage("The user <@!" + ID + "> is now banned from using the bot.").queue();
}
return new CommandResult(CommandResultType.SUCCESS);
} else {
throw new IllegalArgumentException("This should never happen");
}
} catch (SQLException e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
-
- /*for (int i = 0; i < DiscordBot.reportedlist.size(); i++) {
- String[] randrp = DiscordBot.reportedlist.get(i).split(" ");
- if (randrp[0].contains(author.getId()) && randrp[1].contains(SID)) {
- return new CommandResult(CommandResultType.FAILURE, "You cannot report a user more than once.");
- }
- }
- boolean banned = false;
- boolean contains = false;
- for (int i = 0; i < DiscordBot.playerreportlist.size(); i++) {
- if (DiscordBot.playerreportlist.get(i).contains(SID)) {
- contains = true;
- }
- }
- if (contains == false) {
- DiscordBot.playerreportlist.add(SID + " " + "1");
- times = 1;
- FileWriter fileWriter = null;
- BufferedWriter bufferedWriter;
- try {
- fileWriter = new FileWriter(DiscordBot.pfile, true);
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- try {
- bufferedWriter = new BufferedWriter(fileWriter);
- bufferedWriter.write(SID + " " + "1" + "\r\n");
- bufferedWriter.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- } else {
- // System.out.println("Got record");//debug
- for (int i = 0; i < DiscordBot.playerreportlist.size(); i++) {
- String[] pandt = DiscordBot.playerreportlist.get(i).split(" ");
- if (pandt[0].contains(SID)) {
- times = Long.parseLong(pandt[1]);
- // System.out.println(times); //debug
- if (times < 5) {
- times = times + (long) 1;
- // System.out.println(times); //debug
- if (times == 5) {
- DiscordBot.BannedID.add(Long.toString(ID));
- banned = true;
- }
- DiscordBot.playerreportlist.set(i, SID + " " + Long.toString(times));
- Path fp = Paths.get(System.getProperty("user.dir"), "PlayerReports.txt");
- try {
- List<String> fileContent = new ArrayList<>(
- Files.readAllLines(fp, StandardCharsets.UTF_8));
-
- for (int f = 0; f < fileContent.size(); f++) {
- if (fileContent.get(f).startsWith(SID)) {
- fileContent.set(f, SID + " " + Long.toString(times));
- break;
- }
- }
-
- Files.write(fp, fileContent, StandardCharsets.UTF_8);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- break;
- } else {
- if (!DiscordBot.BannedID.contains(String.valueOf(ID))) {
- DiscordBot.BannedID.add(Long.toString(ID));
- }
- return new CommandResult(CommandResultType.FAILURE, "The user <@!" + ID
- + "> had enough reports therefore he is banned from using this bot.");
- }
- }
- }
- }
- DiscordBot.reportedlist.add(author.getId() + " " + SID);
- channel.sendMessage("You have successfully reported <@!" + ID + ">.\nThe user has been reported for "
- + times + "/5 times.\n").queue();
- String addinfo = null;
- if (banned == true) {
- channel.sendMessage("The user <@!" + ID + "> is now banned from using the bot.").queue();
- addinfo = channel.getGuild().getMemberById(SID).getEffectiveName() + " (" + SID
- + ") is banned from the bot.";
- }
- return new CommandResult(CommandResultType.SUCCESS, addinfo);*/
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/info/CityInfo.java b/src/me/despawningbone/discordbot/command/info/CityInfo.java
index 8a831d8..2826901 100644
--- a/src/me/despawningbone/discordbot/command/info/CityInfo.java
+++ b/src/me/despawningbone/discordbot/command/info/CityInfo.java
@@ -1,272 +1,140 @@
package me.despawningbone.discordbot.command.info;
import java.awt.Color;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import me.despawningbone.discordbot.utils.MiscUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
public class CityInfo extends Command {
public CityInfo() {
this.alias = Arrays.asList("ci", "weather");
this.desc = "Search for info about a city!"; //"Search for info about the city the address is in!";
this.usage = "<address/search words>";
for (String country : Locale.getISOCountries()) {
Locale locale = new Locale("en", country);
countryCodes.put(locale.getDisplayCountry(Locale.ENGLISH), locale.getCountry());
}
this.examples = Arrays.asList("hong kong", "tokyo"); //"HK", "akihabara");
}
HashMap<String, String> countryCodes = new HashMap<>();
NumberFormat formatter = new DecimalFormat("#0.00");
- //private final String flickrAPI = DiscordBot.tokens.getProperty("flickr");
-
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
if(args.length < 1) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please input a city name."); //or a address.");
} else {
channel.sendTyping().queue();
String sword = String.join(" ", args);
try {
- /*JSONTokener georesult = null;
- InputStream geostream = null;
- String search = URLEncoder.encode(sword, "UTF-8");
- URL geocode = null;
- try {
- geocode = new URL("https://maps.googleapis.com/maps/api/geocode/json?address=" + search + "&key=" + AudioPlayer.GAPI + "&language=en");
- geostream = geocode.openStream();
- } catch (IOException e) {
- e.printStackTrace();
- }
- georesult = new JSONTokener(geostream);
- JSONObject geomain = new JSONObject(georesult);
- JSONArray resultList = geomain.getJSONArray("results");
- if(resultList.isNull(0)) {
- channel.sendMessage("Unfortunately there is no results :cry:").queue();
- return new CommandResult(CommandResultType.NORESULT);
- }
- JSONObject firstResult = resultList.getJSONObject(0);
- JSONObject loc = firstResult.getJSONObject("geometry").getJSONObject("location");
- //String formattedAddr = firstResult.getString("formatted_address");
- JSONArray addrComponents = firstResult.getJSONArray("address_components");
- String formattedAddr = "", addr = firstResult.getString("formatted_address");
- String countryShort = null; String region = null; String locality = null; String country = null; String colarea = null;
- boolean stop = false;
- for(int i = 0; i < addrComponents.length(); i++) {
- JSONObject component = addrComponents.getJSONObject(i);
- String compname = component.getString("long_name");
- if(!stop) {
- if(i == addrComponents.length() - 1) {
- formattedAddr += compname;
- } else {
- formattedAddr += compname + ", ";
- }
- }
- List<Object> types = component.getJSONArray("types").toList();
- if(types.contains("country")) {
- countryShort = component.getString("short_name");
- country = compname;
- if(i == 0) {
- channel.sendMessage("You need to specify which part of the country you want to get the info from.").queue();
- return new CommandResult(CommandResultType.FAILURE, "Address is a country");
- }
- } else if(types.contains("continent")) {
- if(i == 0) {
- channel.sendMessage("You need to specify which part of the continent you want to get the info from.").queue();
- return new CommandResult(CommandResultType.FAILURE, "Address is a continent");
- }
- } else if(types.contains("postal_code")) {
- if(i == 0) {
- formattedAddr = addr;
- stop = true;
- }
- } else if(types.contains("administrative_area_level_1")) {
- region = compname;
- } else if(types.contains("locality")) {
- locality = compname;
- } else if(types.contains("colloquial_area")) {
- colarea = compname;
- } else if(types.contains("natural_feature") && addrComponents.length() == 1) {
- channel.sendMessage("Search civilized locations please :joy:").queue();
- return new CommandResult(CommandResultType.FAILURE, "Address is natural");
- }
- }
- if(region == null) {
- if(stop) {
- region = country;
- } else {
- if(locality.equals("Singapore")) {
- formattedAddr = addr;
- }
- region = colarea;
- if(locality != null) region = locality;
- }
- }
- double lat = loc.getDouble("lat");
- double lng = loc.getDouble("lng");
- JSONTokener timeresult = null;
- InputStream timestream = null;
- URL timezone = null;
- Timestamp timestamp = new Timestamp(System.currentTimeMillis());
- long sec = Math.round(timestamp.getTime() / 1000.0);
- try { //can deprecate this since the new weather scrape has local time, but there wont be a name for the timezone anymore
- timezone = new URL("https://maps.googleapis.com/maps/api/timezone/json?location=" + lat + "," + lng + "&timestamp=" + sec + "&key=" + AudioPlayer.GAPI + "&language=en");
- timestream = timezone.openStream();
- } catch (IOException e) {
- e.printStackTrace();
- }
- timeresult = new JSONTokener(timestream);
- JSONObject timemain = new JSONObject(timeresult);
- String timeZoneName = timemain.getString("timeZoneName");
- int rawOffset = timemain.getInt("rawOffset");
- int dstOffset = timemain.getInt("dstOffset");
- ZonedDateTime zone = ZonedDateTime.now(ZoneOffset.ofTotalSeconds(rawOffset + dstOffset));
- int hours = (rawOffset + dstOffset) / 60 / 60;*/
-
boolean hasWeather = true;
JSONObject info = null;
String wQualifiedName = "", woeid = "", lng = "", lat = "", region = "", countryShort = ""; TimeZone timezone = null;
- /*try {
- URLConnection con = new URL("https://api.flickr.com/services/rest/?method=flickr.places.find&api_key=" + flickrAPI + "&query=" + URLEncoder.encode(sword, "UTF-8") + "&format=json&nojsoncallback=1").openConnection();
- con.setRequestProperty("Accept-Language", "en");
- JSONArray warray = new JSONObject(new JSONTokener(con.getInputStream())).getJSONObject("places").getJSONArray("place");
- int index;
- for(index = 0; index < warray.length(); index++) {
- if(warray.getJSONObject(index).has("timezone")) {
- break;
- }
- }
- JSONObject wsearch = warray.getJSONObject(index);
- woeid = wsearch.getString("woeid"); //flickr api, using generated api key (will it expire?) //highest accuracy so far
- //wQualifiedName = wsearch.getString("_content"); //too short
- ArrayList<String> pSplit = new ArrayList<>(Arrays.asList(URLDecoder.decode(wsearch.getString("place_url"), "UTF-8").substring(1).split("/")));
- if(!pSplit.get(pSplit.size() - 1).equals(wsearch.getString("woe_name"))) {
- pSplit.add(wsearch.getString("woe_name"));
- }
- Collections.reverse(pSplit);
- wQualifiedName = String.join(", ", pSplit);
- timezone = TimeZone.getTimeZone(wsearch.getString("timezone"));
- lat = wsearch.getString("latitude");
- lng = wsearch.getString("longitude");
- String[] rSplit = wQualifiedName.split(", ");
- region = rSplit.length > 1 ? rSplit[rSplit.length - 2] : rSplit[0];
- countryShort = countryCodes.get(rSplit[rSplit.length - 1].trim());
- } catch(IOException e) {
- return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
- } catch (JSONException e) {
- //e.printStackTrace();
- return new CommandResult(CommandResultType.NORESULT);
- }*/ //FLICKR DED
try {
URLConnection sCon = new URL("https://www.yahoo.com/news/_tdnews/api/resource/WeatherSearch;text=" + URLEncoder.encode(sword, "UTF-8") + "?returnMeta=true").openConnection();
sCon.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0");
JSONObject wsearch = new JSONObject(new JSONTokener(sCon.getInputStream())).getJSONArray("data").getJSONObject(0);
woeid = String.valueOf(wsearch.getInt("woeid")); //yahoo scrape
lat = String.valueOf(wsearch.getDouble("lat"));
lng = String.valueOf(wsearch.getDouble("lon"));
wQualifiedName = wsearch.getString("qualifiedName");
countryShort = countryCodes.get(wsearch.getString("country"));
- region = wsearch.getString("city");
+ region = wQualifiedName.split(",")[wQualifiedName.split(",").length - 2]; //get second highest level, highest should always be country code
timezone = TimeZone.getTimeZone(new JSONObject(new JSONTokener(new URL("https://api.internal.teleport.org/api/locations/" + lat + "," + lng + "/?embed=location:nearest-cities/location:nearest-city/city:timezone").openStream())).getJSONObject("_embedded").getJSONArray("location:nearest-cities").getJSONObject(0).getJSONObject("_embedded").getJSONObject("location:nearest-city").getJSONObject("_embedded").getJSONObject("city:timezone").getString("iana_name"));
//can use metaweather, but not accurate enough
//can also broaden the scope for yahoo scrape for it to work better
//JSONObject wsearch = new JSONObject(new JSONTokener(new URL("https://api.flickr.com/services/rest/?method=flickr.places.findByLatLon&api_key=bdaafeafab62267931d920dda27a4f90&lat=" + lat + "&lon=" + lng + "&format=json&nojsoncallback=1").openStream())).getJSONObject("places").getJSONArray("place").getJSONObject(0); //gonna use flickr find instead
URLConnection iCon = new URL("https://www.yahoo.com/news/_tdnews/api/resource/WeatherService;woeids=[" + woeid + "]?lang=en-US&returnMeta=true").openConnection();
iCon.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0");
info = new JSONObject(new JSONTokener(iCon.getInputStream())).getJSONObject("data").getJSONArray("weathers").getJSONObject(0);
} catch(IOException e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
} catch(JSONException e) {
e.printStackTrace();
return new CommandResult(CommandResultType.NORESULT);
//hasWeather = false;
}
- /*String ftimezone = timeZoneName + " (UTC" + (Math.signum(hours) == 1 || Math.signum(hours) == 0 ? "+" + hours : hours) + ")";
- if(ftimezone.length() < 34) {
- ftimezone += String.join("", Collections.nCopies(34 - ftimezone.length(), " "));
- }*/
+
Date date = new Date();
//System.out.println(info);
EmbedBuilder embedmsg = new EmbedBuilder();
embedmsg.setAuthor("Info for " + wQualifiedName, null, null);
embedmsg.setColor(new Color(100, 0, 255));
- //embedmsg.setFooter("Weather info last updated: " + info.getString("lastBuildDate") , null);
embedmsg.addField("Country", MiscUtils.countryNameToUnicode(countryShort), true);
embedmsg.addField("Region", region, true);
embedmsg.addField("Current time", OffsetDateTime.now(timezone.toZoneId()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ssa").withLocale(Locale.ENGLISH)).trim(), true);
long hours = (timezone.getOffset(date.getTime())/1000/60/60);
embedmsg.addField("Timezone" , timezone.getDisplayName(timezone.inDaylightTime(date), TimeZone.LONG, Locale.ENGLISH) + " (UTC" + (Math.signum(hours) == 1 || Math.signum(hours) == 0 ? "+" + hours : hours) + ")" + "\u1160", true); //FLICKR DED
String footer = "Weather info not available";
if (hasWeather) { //use another api if weather info not available?
JSONObject obs = info.getJSONObject("observation"); JSONObject temp = obs.getJSONObject("temperature"); JSONObject forecast = info.getJSONObject("forecasts").getJSONArray("daily").getJSONObject(0);
if(temp.has("now")) {
embedmsg.addField("Temperature", fToC(temp.getInt("now")) + "°C (↑" + fToC(temp.getInt("high")) + "°C | ↓" + fToC(temp.getInt("low")) + "°C)", true);
embedmsg.addField("Humidity", obs.getInt("humidity") + "% (Chance of rain: " + forecast.getInt("precipitationProbability") + "%)", true);
embedmsg.addField("Visibility", miToKm(obs.getDouble("visibility")) + "km (" + obs.getString("conditionDescription") + ")", true);
embedmsg.addField("Atmospheric pressure", formatter.format(obs.getDouble("barometricPressure") / 0.029530) + "millibars", true);
embedmsg.addField("Wind speed", miToKm(obs.getDouble("windSpeed")) + "km/h", true);
embedmsg.addField("Wind direction", obs.getInt("windDirection") + "° (" + obs.getString("windDirectionCode") + ")", true);
embedmsg.addField("Feels Like", fToC(temp.getInt("feelsLike")) + "°C", true);
embedmsg.addField("UV index", obs.getInt("uvIndex") + " (" + obs.getString("uvDescription") + ")", true);
embedmsg.addField("Sunrise", MiscUtils.convertMillis(info.getJSONObject("sunAndMoon").getLong("sunrise") * 1000).substring(0, 5), true);
embedmsg.addField("Sunset", MiscUtils.convertMillis(info.getJSONObject("sunAndMoon").getLong("sunset") * 1000).substring(0, 5), true);
String imgUrl = info.getJSONArray("photos").getJSONObject(0).getJSONArray("resolutions").getJSONObject(0).getString("url"); //seems to have dead urls, how fix
embedmsg.setThumbnail(imgUrl.split(":\\/\\/").length > 2 ? "https://" + imgUrl.split(":\\/\\/")[2] : imgUrl);
footer = "Weather info last updated: " + OffsetDateTime.parse(obs.getJSONObject("observationTime").getString("timestamp")).format(DateTimeFormatter.RFC_1123_DATE_TIME)
.replace("GMT", timezone.getDisplayName(timezone.inDaylightTime(date), TimeZone.SHORT, Locale.ENGLISH)); //+ " | " + wQualifiedName;
//add weather provider to footer?
}
}
embedmsg.addField("Latitude", lat, true);
embedmsg.addField("Longitude", lng, true);
embedmsg.setFooter(footer, null);
try {
MessageEmbed fmsg = embedmsg.build();
channel.sendMessage(fmsg).queue();
} catch(InsufficientPermissionException e2) {
return new CommandResult(CommandResultType.FAILURE, "Unfortunately, the bot is missing the permission `MESSAGE_EMBED_LINKS` which is required for this command to work.");
}
return new CommandResult(CommandResultType.SUCCESS);
} catch (Exception e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
}
}
private String fToC(int f) { //fucking no metric ree
return formatter.format((f-32)*5.0/9);
}
private String miToKm(double mile) {
return formatter.format(mile*1.609344);
}
}
diff --git a/src/me/despawningbone/discordbot/command/info/CurrencyConvert.java b/src/me/despawningbone/discordbot/command/info/CurrencyConvert.java
index 60c3686..b2a6e52 100644
--- a/src/me/despawningbone/discordbot/command/info/CurrencyConvert.java
+++ b/src/me/despawningbone/discordbot/command/info/CurrencyConvert.java
@@ -1,121 +1,82 @@
package me.despawningbone.discordbot.command.info;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
/*import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;*/
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class CurrencyConvert extends Command {
public CurrencyConvert() {
this.alias = Arrays.asList("currency", "cc");
this.desc = "convert a currency to another!";
this.usage = "<from> <to> [amount]";
this.remarks = Arrays.asList("The currency units use the format of ISO 4217. For the list, see below:", "https://en.wikipedia.org/wiki/ISO_4217");
this.examples = Arrays.asList("HKD USD", "EUR SGD 100");
}
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
String fromc = null;
String toc = null;
String num = null;
try {
fromc = args[0].toUpperCase();
toc = args[1].toUpperCase();
} catch (ArrayIndexOutOfBoundsException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter 2 currencies.");
}
try { //there is a lot more info, use them too?
InputStream stream = new URL("https://query1.finance.yahoo.com/v8/finance/chart/"+ fromc + toc + "=X?range=6h&includePrePost=false&interval=1m").openStream();
JSONObject main = new JSONObject(new JSONTokener(stream)).getJSONObject("chart").getJSONArray("result").getJSONObject(0);
double rate = 0;
try {
List<Object> close = main.getJSONObject("indicators").getJSONArray("quote").getJSONObject(0).getJSONArray("close").toList();
close.removeAll(Collections.singleton(null));
rate = (double) close.get(close.size() - 1);
} catch (JSONException e) {
rate = main.getJSONObject("meta").getDouble("previousClose");
//rate += new JSONObject(new JSONTokener(new URL("https://query1.finance.yahoo.com/v1/finance/lookup?formatted=true&lang=en-US&region=US&query=" + fromc + toc + "=x&type=all&count=25&start=0&corsDomain=finance.yahoo.com").openStream()))
//.getJSONObject("finance").getJSONArray("result").getJSONObject(0).getJSONArray("documents").getJSONObject(0).getJSONObject("regularMarketChange").getDouble("raw");
}
if(rate == 1) {
- //throw new NullPointerException("Invalid currency conversion!");
return new CommandResult(CommandResultType.INVALIDARGS, "Invalid currency conversion!");
}
try {
num = args[2];
} catch (ArrayIndexOutOfBoundsException e) {
num = "1";
}
double f = rate * Double.parseDouble(num);
channel.sendMessage(num + " " + fromc.toUpperCase() + " = " + new DecimalFormat("#.####").format(f) + " " + toc.toUpperCase()).queue();
return new CommandResult(CommandResultType.SUCCESS);
} catch (IOException e) {
if(e instanceof FileNotFoundException) {
return new CommandResult(CommandResultType.INVALIDARGS, "Invalid currency. See the help for the list of available currencies.");
} else {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
} catch (NumberFormatException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Invalid amount.");
}
-
- /*SCRAPE DEPRECATED*/
-
- /*try { // again, not pretty good to scrape but thats the only way to get the ever updating yahoo finance data
- Document doc = Jsoup.connect("https://hk.finance.yahoo.com/quote/" + fromc + toc + "=X").get();
- // System.out.println(doc);
- try {
- String rate = doc.select("span[data-reactid=\"35\"]").first().text().replace(",", "");
- // String cc = doc.select("div[data-reactid=\"6\"] h1").first().text().split(" ")[0].replace("/", "");
- // System.out.println(cc);
- if (Double.parseDouble(rate) == 1 //!cc.equals(fromc + toc) ) {
- throw new NullPointerException();
- }
- boolean nonum = false;
- try {
- num = args[2];
- } catch (ArrayIndexOutOfBoundsException e) {
- nonum = true;
- num = "1";
- }
- String finalrate;
- if (!nonum) {
- double tempn = Double.parseDouble(num);
- double tempr = Double.parseDouble(rate);
- finalrate = String.valueOf(tempn * tempr);
- } else {
- finalrate = rate;
- }
- channel.sendMessage(num + " " + fromc.toUpperCase() + " = " + finalrate + " " + toc.toUpperCase())
- .queue();
- return new CommandResult(CommandResultType.SUCCESS, null);
- } catch (NullPointerException | NumberFormatException e) {
- channel.sendMessage("Invalid currency.").queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }
- } catch (IOException e) {
- return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
- }*/
}
}
diff --git a/src/me/despawningbone/discordbot/command/info/Fandom.java b/src/me/despawningbone/discordbot/command/info/Fandom.java
index 930173d..d9b7e72 100644
--- a/src/me/despawningbone/discordbot/command/info/Fandom.java
+++ b/src/me/despawningbone/discordbot/command/info/Fandom.java
@@ -1,106 +1,106 @@
package me.despawningbone.discordbot.command.info;
import java.awt.Color;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.time.Instant;
import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class Fandom extends Command {
public Fandom() {
this.desc = "Search across all the fan-made wikis!";
this.alias = Arrays.asList("wikia", "gamepedia"); //gamepedia is now fandom basically
this.usage = "<wiki name>: <search> [| index]";
this.examples = Arrays.asList("zelda: gate of time", "clockwork planet: ryuZU", "angel beats: kanade");
}
- @Override //query for details using future too? since i already have to make 2 queries, making 3 in parallel wont make it much slower; the only concern is rate limit //already doing sequential 3 queries, aint too slow so its fine
+ @Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
channel.sendTyping().queue();
if (args.length < 1) {
return new CommandResult(CommandResultType.INVALIDARGS, "Invalid input, check help for more info.");
}
try {
String[] init = String.join(" ", args).split(":", 2);
if(init.length < 2) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please use a colon to seperate the wiki and the search query!");
}
//get index
String[] split = init[1].split(" \\| ");
String sword = split[0];
int num = 0;
if (split.length > 1) {
try {
num = Integer.parseInt(split[1]) - 1;
if(num < 0) throw new NumberFormatException();
} catch (NumberFormatException e) {
channel.sendMessage("Invalid index inputted. Defaulting to the first result...").queue();
num = 0;
}
}
//bruh the gamepedia merge killed a ton of the actual good UCP/nirvana API controller endpointss
//now i gotta use wack substitutions
//search - since SearchApiController is now gone i gotta use the other ones
String search = URLEncoder.encode(sword.trim(), "UTF-8");
HttpURLConnection url = null;
String wiki = init[0].replaceAll("[^\\p{L}\\p{N} ]+", "").replaceAll(" ", "-").toLowerCase();
//the wikia domain is still in use; no need to swap to fandom.com for now
//alternative search endpoint (more of an autocomplete only but much faster): "https://" + wiki + ".wikia.com/wikia.php?controller=LinkSuggest&method=getLinkSuggestions&format=json&query=" + search
url = (HttpURLConnection) new URL("https://" + wiki + ".wikia.com/api.php?action=query&format=json&list=search&srsearch=" + search).openConnection();
if(url.getResponseCode() == 404) {
return new CommandResult(CommandResultType.FAILURE, "Unknown wiki name!"); //404 means unknown wiki now
}
//get result
int id;
try {
JSONObject result = new JSONObject(new JSONTokener(url.getInputStream()));
id = result.getJSONObject("query").getJSONArray("search").getJSONObject(num).getInt("pageid");
} catch(JSONException e) {
return new CommandResult(CommandResultType.NORESULT, "it in the " + init[0] + " wiki");
}
//fetch details about page; way worse formatting than AsSimpleJson but hey its gone what can i do
JSONObject details = new JSONObject(new JSONTokener(new URL("https://" + wiki + ".wikia.com/api/v1/Articles/Details?abstract=500&ids=" + id).openStream()));
JSONObject info = details.getJSONObject("items").getJSONObject(String.valueOf(id)); //TODO make async
EmbedBuilder eb = new EmbedBuilder();
eb.setTitle(info.getString("title"), details.getString("basepath") + info.getString("url"));
eb.setAuthor(StringUtils.capitalize(init[0]) + " wiki", details.getString("basepath"));
//only use until the last full stop before table of content or end for slightly better formatting
//there might be false positives for table of content detection since its just checking 1 after full stop, but honestly rarely less details > commonly being ugly af
String desc = info.getString("abstract").replaceAll("^(?:(.*?\\.) ?1 .*|(.*\\.) .*?)$", "$1$2"); //greedy if table of content is present, else lazy to get the last
eb.setDescription(desc.matches(".*\\.$") ? desc : (desc + "...")); //if everything fails (aka last char aint a full stop) give it the good ol ... treatment
if(info.has("comments")) eb.addField("Comments", String.valueOf(info.getInt("comments")), false);
if(!info.isNull("thumbnail")) eb.setThumbnail(info.getString("thumbnail").substring(0, info.getString("thumbnail").indexOf("/revision/"))); //get full img by trimming revision path
eb.setFooter("Last edited by " + info.getJSONObject("revision").getString("user"), null);
eb.setTimestamp(Instant.ofEpochSecond(Long.parseLong(info.getJSONObject("revision").getString("timestamp"))));
eb.setColor(new Color(0, 42, 50));
channel.sendMessage(eb.build()).queue();
return new CommandResult(CommandResultType.SUCCESS); //add searched result name?
} catch (Exception e) {
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/info/Translate.java b/src/me/despawningbone/discordbot/command/info/Translate.java
index 763628d..e7c44ea 100644
--- a/src/me/despawningbone/discordbot/command/info/Translate.java
+++ b/src/me/despawningbone/discordbot/command/info/Translate.java
@@ -1,116 +1,117 @@
package me.despawningbone.discordbot.command.info;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import org.jsoup.Jsoup;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.HttpStatusException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class Translate extends Command {
public Translate() {
this.desc = "Translate some sentences!";
this.usage = "[-fromlang] <sentence> [-tolang]";
this.remarks = Arrays.asList("Supported Languages: `en, ja, zh, de, es, fr, it, ru, pl, pt, nl`");
this.examples = Arrays.asList("-ja あなたも文化人だと思います", "-es despacito");
this.alias = Arrays.asList("tl");
executor.scheduleAtFixedRate(() -> refresh(), 0, 300, TimeUnit.SECONDS); //5 mins refresh
}
private int id = (ThreadLocalRandom.current().nextInt(1000, 10000) + 1) * 10000 + 1;
private String cookie = null, agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0";
private JSONObject cVars = null;
final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("tl-scheduler-%d").build());
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) {
if(args.length < 0) return new CommandResult(CommandResultType.INVALIDARGS, "Please enter something to translate!");
try {
String langF = "auto", langT = "EN", query = String.join(" ", args).replaceAll("\n", " ").replace("-", ""); //since it hates new lines and hyphens apparently
if(Arrays.asList("-en", "-ja", "-zh", "-de", "-es", "-fr", "-it", "-ru", "-pl", "-pt", "-nl").contains(args[0].toLowerCase())) {
langF = args[0].substring(1).toUpperCase();
query = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
}
if(Arrays.asList("-en", "-ja", "-zh", "-de", "-es", "-fr", "-it", "-ru", "-pl", "-pt", "-nl").contains(args[args.length - 1].toLowerCase())) {
langT = args[args.length - 1].substring(1).toUpperCase();
query = query.substring(0, query.length() - 3);
}
if((args.length < 5 ? query.length() > 40 : args.length > 20)) return new CommandResult(CommandResultType.INVALIDARGS, "Please type a shorter phrase to translate!");
//need OPTION call before calling this?
//req
- Connection con = Jsoup.connect("https://www2.deepl.com/jsonrpc").userAgent(agent)
+ Connection con = Jsoup.connect("https://www2.deepl.com/jsonrpc?method=LMT_handle_jobs").userAgent(agent)
.header("Content-type", "application/json").ignoreContentType(true)
.requestBody("{\"jsonrpc\":\"2.0\",\"method\": \"LMT_handle_jobs\",\"params\":{\"jobs\":[{\"kind\":\"default\",\"raw_en_sentence\":\"" + query + "\",\"raw_en_context_before\":[],\"raw_en_context_after\":[],\"preferred_num_beams\":4" + ((args.length < 2 ? query.length() > 5 : args.length > 5) ? "" : ",\"quality\":\"fast\"") + "}],\"commonJobParams\":{}"
+ ",\"lang\":{\"user_preferred_langs\":[\"EN\"],\"source_lang_user_selected\":\"" + langF + "\",\"target_lang\":\"" + langT + "\"},\"priority\":1,\"timestamp\":" + OffsetDateTime.now().toEpochSecond() + "000},\"id\":" + id++ + "}");
if(cookie != null) con.cookie("LMTBID", cookie);
Response resp = con.method(Method.POST).execute();
if(resp.hasCookie("LMTBID")) cookie = resp.cookie("LMTBID"); //set cookies; only LMTBID is useful, and its set on first call to jsonrpc
//formatting
JSONObject main = new JSONObject(new JSONTokener(resp.body())).getJSONObject("result");
EmbedBuilder eb = new EmbedBuilder();
eb.setColor(0x0f2b46);
eb.setTitle("Translation: " + (langF.equals("auto") ? main.getString("source_lang") + "(detected)" : langF) + " -> " + main.getString("target_lang"));
eb.addField("Original", query, true);
String tl = "";
for(Object obj : main.getJSONArray("translations").getJSONObject(0).getJSONArray("beams")) {
String p = ((JSONObject) obj).getString("postprocessed_sentence");
if(tl.isEmpty()) tl = p + "\n";
else tl += "*" + p + "*\n";
}
eb.addField("Translated", tl, true);
eb.setFooter("Translated by DeepL", "https://egress.storeden.net/gallery/5a2577c9ffe48e7e4b418464");
eb.setTimestamp(OffsetDateTime.now());
channel.sendMessage(eb.build()).queue();
return new CommandResult(CommandResultType.SUCCESS);
} catch(IOException e) {
if(e instanceof HttpStatusException) //aka pending code fix
return new CommandResult(CommandResultType.FAILURE, "The translator is currently temporarily unavailable, please try again later.");
-
+
return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e));
}
}
private void refresh() {
try {
- Connection con = Jsoup.connect("https://www.deepl.com/PHP/backend/clientState.php?request_type=jsonrpc&il=EN").userAgent(agent)
- .requestBody("{\"jsonrpc\":\"2.0\",\"method\":\"getClientState\",\"params\":{\"v\":\"20180814\"" + (cVars == null ? "" : ",\"clientVars\":" + cVars.toString()) + "},\"id\":" + id++ + "}");
+ Connection con = Jsoup.connect("https://www.deepl.com/PHP/backend/clientState.php?request_type=jsonrpc&il=EN&method=getClientState").userAgent(agent)
+ .requestBody("{\"jsonrpc\":\"2.0\",\"method\":\"getClientState\",\"params\":{\"v\":\"20180814\"" + ",\"clientVars\":" + (cVars == null ? "{}" : cVars.toString()) + "},\"id\":" + id++ + "}");
if(cookie != null) con.cookie("LMTBID", cookie);
-
+
JSONObject json = new JSONObject(new JSONTokener(con.ignoreContentType(true).post().text()));
//System.out.println(json);
- if(cVars == null) cVars = json.getJSONObject("result").getJSONObject("clientVars");
+ if(cVars == null) cVars = json.getJSONObject("result").getJSONObject("clientVars");
} catch (IOException e) {
e.printStackTrace();
+ id--; //set it back down one
}
}
}
diff --git a/src/me/despawningbone/discordbot/command/misc/BaseConvert.java b/src/me/despawningbone/discordbot/command/misc/BaseConvert.java
index 800f6e0..8fd0329 100644
--- a/src/me/despawningbone/discordbot/command/misc/BaseConvert.java
+++ b/src/me/despawningbone/discordbot/command/misc/BaseConvert.java
@@ -1,113 +1,56 @@
package me.despawningbone.discordbot.command.misc;
import java.util.Arrays;
import me.despawningbone.discordbot.command.Command;
import me.despawningbone.discordbot.command.CommandResult;
import me.despawningbone.discordbot.command.CommandResult.CommandResultType;
import me.despawningbone.discordbot.utils.MiscUtils;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.User;
public class BaseConvert extends Command {
public BaseConvert() {
this.alias = Arrays.asList("bc");
this.desc = "convert integers of a base to another base!";
this.usage = "[frombase] <base> <int>";
this.examples = Arrays.asList("2 100", "16 8 FF");
}
@Override
public CommandResult execute(TextChannel channel, User author, Message msg, String[] args) { //base 1 is weird, fix?
String x = "0";
long base = 10;
long frombase = 10;
try {
- if (args.length < 3) {
- try {
- base = Long.parseLong(args[0]);
- x = args[1];
- } catch (ArrayIndexOutOfBoundsException e) {
- return new CommandResult(CommandResultType.INVALIDARGS, "Please enter" + (args.length < 1 ? "something :joy:" : "a value to convert."));
- } catch (NumberFormatException e) {
- base = MiscUtils.nameToBase(args[0]);
- }
- } else {
+ if(args.length < 2)
+ return new CommandResult(CommandResultType.INVALIDARGS, "Please enter " + (args.length < 1 ? "something :joy:" : "a value to convert."));
+
+ if (args.length < 3) { //only specify to base
+ try { base = Long.parseLong(args[0]); } catch (NumberFormatException e) { base = MiscUtils.nameToBase(args[0]); }
+ x = args[1];
+ } else { //specify both bases
try { frombase = Long.parseLong(args[0]); } catch (NumberFormatException e) { frombase = MiscUtils.nameToBase(args[0]); }
try { base = Long.parseLong(args[1]); } catch (NumberFormatException e) { base = MiscUtils.nameToBase(args[1]); }
x = args[2];
}
- if (base > 30 || frombase > 30) {
+
+ if (base > 30 || frombase > 30)
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a base smaller than 30.");
- }
+
try {
channel.sendMessage("Base" + MiscUtils.longToSubscript(frombase) + ": `" + x.toUpperCase() + "`\n" + "Base"
+ MiscUtils.longToSubscript(base) + ": `"
+ Long.toString(Long.parseLong(x, (int) frombase), (int) base).toUpperCase() + "`").queue();
return new CommandResult(CommandResultType.SUCCESS);
} catch (NumberFormatException e) {
return new CommandResult(CommandResultType.INVALIDARGS, "Please enter a valid value within the base range specified.");
}
} catch (IllegalArgumentException e) {
return new CommandResult(CommandResultType.INVALIDARGS, e.getMessage());
}
-
- /*DEPRECATED OLD CODE*/
-
- /*try {
- if (args.length < 2) {
- try {
- base = Long.parseLong(msg.getContentDisplay().split(" ")[2]);
- } catch (ArrayIndexOutOfBoundsException e) {
- channel.sendMessage("Please enter something :joy:").queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }
- } else {
- frombase = Long.parseLong(msg.getContentDisplay().split(" ")[2]);
- base = Long.parseLong(msg.getContentDisplay().split(" ")[3]);
- }
- if (base > 30 || frombase > 30) {
- channel.sendMessage("Please enter a base smaller than 30.").queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }
- } catch (NumberFormatException e) {
- String sbase = msg.getContentDisplay().split(" ")[2];
- try {
- if (msg.getContentDisplay().split(" ").length > 4) {
- frombase = MiscUtils.nameToBase(sbase);
- base = MiscUtils.nameToBase(msg.getContentDisplay().split(" ")[3]);
- } else {
- base = MiscUtils.nameToBase(sbase);
- }
- } catch (NullPointerException | IllegalArgumentException e1) {
- if (e1 instanceof IllegalArgumentException) {
- channel.sendMessage(e1.getMessage()).queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }
- return new CommandResult(CommandResultType.ERROR, ExceptionUtils.getStackTrace(e1));
- }
- }
- if (msg.getContentDisplay().split(" ").length < 5) {
- try {
- x = msg.getContentDisplay().split(" ", 4)[3];
- } catch (ArrayIndexOutOfBoundsException e) {
- channel.sendMessage("Please enter a value to convert.").queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }
- } else {
- x = msg.getContentDisplay().split(" ", 5)[4];
- }
- try {
- channel.sendMessage("Base" + MiscUtils.longToSubscript(frombase) + ": `" + x + "`\n" + "Base"
- + MiscUtils.longToSubscript(base) + ": `"
- + Long.toString(Long.parseLong(x, (int) frombase), (int) base).toUpperCase() + "`").queue();
- return new CommandResult(CommandResultType.SUCCESS, null);
- } catch (NumberFormatException e) {
- channel.sendMessage("Please enter a valid positive integer within the base range specified.").queue();
- return new CommandResult(CommandResultType.INVALIDARGS, null);
- }*/
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Mar 15, 3:05 AM (17 h, 40 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
36/c7/54431344e5684a22674b3ce54788

Event Timeline