diff --git a/pom.xml b/pom.xml index 996abd4..d4f019a 100644 --- a/pom.xml +++ b/pom.xml @@ -11,8 +11,8 @@ UTF-8 UTF-8 - 8 - 8 + 17 + 17 @@ -45,15 +45,6 @@ - - - maven-compiler-plugin - 2.3.2 - - 1.8 - 1.8 - - @@ -69,7 +60,7 @@ net.dv8tion JDA - 5.0.0-alpha.17 + 5.0.0-alpha.18 org.yaml @@ -116,6 +107,21 @@ json 20220320 + + org.mariadb.jdbc + mariadb-java-client + 3.0.7 + + + org.xerial + sqlite-jdbc + 3.39.2.0 + + + com.zaxxer + HikariCP + 5.0.1 + \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/Config.java b/src/main/java/net/tylermurphy/ken/Config.java index c5a5991..96d5bf5 100644 --- a/src/main/java/net/tylermurphy/ken/Config.java +++ b/src/main/java/net/tylermurphy/ken/Config.java @@ -93,6 +93,8 @@ public class Config { throw new RuntimeException("Unable to finalize loading of config files."); } + this.saveConfig(); + } @SuppressWarnings({"rawtypes", "unchecked"}) diff --git a/src/main/java/net/tylermurphy/ken/Ken.java b/src/main/java/net/tylermurphy/ken/Ken.java index dbdca83..97df266 100644 --- a/src/main/java/net/tylermurphy/ken/Ken.java +++ b/src/main/java/net/tylermurphy/ken/Ken.java @@ -13,6 +13,7 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.tylermurphy.ken.command.Responder; +import net.tylermurphy.ken.database.Database; import net.tylermurphy.ken.music.PlayerManager; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -32,11 +33,13 @@ public class Ken { private final PlayerManager playerManager; private final YouTube youTube; private final Responder responder; + private final Database database; private Ken(){ Ken.instance = this; this.config = Config.create("config.yml"); this.log = LoggerFactory.getLogger(Ken.class); + this.database = new Database(); try { api = JDABuilder.createDefault(config.getString("botToken")) .setActivity(Activity.playing("@Ken | /help")) @@ -93,6 +96,8 @@ public class Ken { public YouTube getYouTube() { return youTube; } + public Database getDatabase() { return database; } + public EmbedBuilder getDefaultEmbed() { EmbedBuilder builder = new EmbedBuilder(); builder.setColor(new Color( diff --git a/src/main/java/net/tylermurphy/ken/command/Responder.java b/src/main/java/net/tylermurphy/ken/command/Responder.java index e7843ee..21ed9ad 100644 --- a/src/main/java/net/tylermurphy/ken/command/Responder.java +++ b/src/main/java/net/tylermurphy/ken/command/Responder.java @@ -13,7 +13,9 @@ import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.requests.restaction.WebhookMessageAction; +import net.dv8tion.jda.api.requests.restaction.WebhookMessageCreateAction; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; +import net.dv8tion.jda.api.utils.FileUpload; import net.tylermurphy.ken.Ken; import net.tylermurphy.ken.util.*; import org.reflections.Reflections; @@ -115,9 +117,6 @@ public class Responder extends ListenerAdapter { return; } - // Defer Reply - event.deferReply().queue(); - // Get slash command options if there are any List args = new ArrayList<>(); event.getOptions().forEach(option -> { @@ -157,18 +156,17 @@ public class Responder extends ListenerAdapter { if(response.error()) { EmbedBuilder builder = Ken.getInstance().getDefaultEmbed() .setColor(Color.RED) - .setTitle(":x: **Error**") .setDescription(response.getMessage()); - event.getHook().sendMessageEmbeds(builder.build()).queue(); + event.replyEmbeds(builder.build()).setEphemeral(true).queue(); } else { - WebhookMessageAction message; + ReplyCallbackAction message; if(response.hasEmbed()) { - message = event.getHook().sendMessageEmbeds(response.getEmbeds()); + message = event.replyEmbeds(response.getEmbeds()); } else { - message = event.getHook().sendMessage(response.getMessage()); + message = event.reply(response.getMessage()); } if(response.hasButtons()) message = message.addActionRow(response.getButtons()); - if(response.hasFile()) message = message.addFile(response.getFile()); + if(response.hasFile()) message = message.addFiles(FileUpload.fromData(response.getFile())); message.queue(); } } catch (Exception e) { @@ -176,7 +174,7 @@ public class Responder extends ListenerAdapter { .setColor(Color.RED) .setTitle(":x: **Error**") .setDescription(e.getCause().getMessage()); - event.getHook().sendMessageEmbeds(builder.build()).queue(); + event.replyEmbeds(builder.build()).setEphemeral(true).queue(); } } diff --git a/src/main/java/net/tylermurphy/ken/command/main/AddSelfRole.java b/src/main/java/net/tylermurphy/ken/command/main/AddSelfRole.java new file mode 100644 index 0000000..3620b41 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/main/AddSelfRole.java @@ -0,0 +1,13 @@ +package net.tylermurphy.ken.command.main; + +import net.tylermurphy.ken.command.Response; + +import javax.management.relation.Role; + +public class AddSelfRole { + +// public Response execute(Role role, String){ +// +// } + +} diff --git a/src/main/java/net/tylermurphy/ken/command/main/DeleteSelfRole.java b/src/main/java/net/tylermurphy/ken/command/main/DeleteSelfRole.java new file mode 100644 index 0000000..de09b9e --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/main/DeleteSelfRole.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.main; + +public class DeleteSelfRole { +} diff --git a/src/main/java/net/tylermurphy/ken/command/main/Roles.java b/src/main/java/net/tylermurphy/ken/command/main/Roles.java new file mode 100644 index 0000000..18403f9 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/command/main/Roles.java @@ -0,0 +1,4 @@ +package net.tylermurphy.ken.command.main; + +public class Roles { +} diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Danbooru.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Danbooru.java index a91e7c5..0e86684 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Danbooru.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Danbooru.java @@ -21,10 +21,9 @@ public class Danbooru { @Option(name="query",description="Search query for danbooru",type= OptionType.STRING,required=true) @Option(name="page",description="Page number for danbooru",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/E621.java b/src/main/java/net/tylermurphy/ken/command/nsfw/E621.java index a454f13..c9ea4fd 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/E621.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/E621.java @@ -21,10 +21,9 @@ public class E621 { @Option(name="query",description="Search query for e621",type= OptionType.STRING,required=true) @Option(name="page",description="Page number for e621",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Gelbooru.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Gelbooru.java index 04062dd..0e3f06b 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Gelbooru.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Gelbooru.java @@ -23,10 +23,9 @@ public class Gelbooru { @Option(name="query",description="Search query for gelbooru",type=OptionType.STRING,required=true) @Option(name="page",description="Page number for gelbooru",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Hentai.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Hentai.java index bfb63c0..593cd3f 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Hentai.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Hentai.java @@ -19,10 +19,9 @@ public class Hentai { @Command(name="hentai", description="Retrieves a random hentai image") @Selection(name="query", description="Type of post you want to get", type=OptionType.STRING, required=true, choices={"ass","bdsm","cum","hentai","femdom","doujin","maid","orgy","nsfwwallpapers","nsfwmobilewallpapers","gif","blowjob","feet","pussy","uglybastard","gangbang","cumslut","glasses","thighs","tentacles","masturbation","school","yuri","succubus"}) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Konachan.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Konachan.java index 9c7bd65..ad031bd 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Konachan.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Konachan.java @@ -24,10 +24,9 @@ public class Konachan { @Option(name="query",description="Search query for konachan",type= OptionType.STRING,required=true) @Option(name="page",description="Page number for konachan",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Rule34.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Rule34.java index a62c301..acab87d 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Rule34.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Rule34.java @@ -23,10 +23,9 @@ public class Rule34 { @Option(name="query",description="Search query for rule34",type=OptionType.STRING,required=true) @Option(name="page",description="Page number for rule34",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/Yandere.java b/src/main/java/net/tylermurphy/ken/command/nsfw/Yandere.java index 1fdad0c..61e3af2 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/Yandere.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/Yandere.java @@ -23,10 +23,9 @@ public class Yandere { @Option(name="query",description="Search query for yande.re",type= OptionType.STRING,required=true) @Option(name="page",description="Page number for yande.re",type= OptionType.INTEGER) public Response execute(GuildMessageChannel channel, List args){ - if(!(channel instanceof TextChannel)) { + if(!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if(!textChannel.isNSFW()){ return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/command/nsfw/nHentai.java b/src/main/java/net/tylermurphy/ken/command/nsfw/nHentai.java index 347eb82..e051b41 100644 --- a/src/main/java/net/tylermurphy/ken/command/nsfw/nHentai.java +++ b/src/main/java/net/tylermurphy/ken/command/nsfw/nHentai.java @@ -22,7 +22,7 @@ import java.util.Map; public class nHentai { - private static class Comic{ + private static class Comic { public int pages; public int id; public String[] page_file_type; @@ -36,10 +36,9 @@ public class nHentai { @Command(name="nhentai", description="Search for a post off of nhentai") @Option(name="query", description="Post id or search for nhentai", type=OptionType.STRING, required=true) public Response execute(GuildMessageChannel channel, List args) { - if (!(channel instanceof TextChannel)) { + if (!(channel instanceof TextChannel textChannel)) { return Response.error("This command can only be used in a text channel"); } - TextChannel textChannel = (TextChannel) channel; if (!textChannel.isNSFW()) { return Response.error("This command can only be used in an NSFW channel"); } diff --git a/src/main/java/net/tylermurphy/ken/database/Database.java b/src/main/java/net/tylermurphy/ken/database/Database.java new file mode 100644 index 0000000..2ce1874 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/Database.java @@ -0,0 +1,33 @@ +package net.tylermurphy.ken.database; + +import net.tylermurphy.ken.Ken; +import net.tylermurphy.ken.database.connections.DatabaseConnection; +import net.tylermurphy.ken.database.connections.MySQLConnection; +import net.tylermurphy.ken.database.connections.SQLiteConnection; + +import java.sql.Connection; +import java.sql.SQLException; + +public class Database { + + private final DatabaseConnection connection; + private final SelfRoleTable selfRoleTable; + + public Database(){ + if(Ken.getInstance().getConfig().getBoolean("database.sqlite")) { + connection = new SQLiteConnection(); + } else { + connection = new MySQLConnection(); + } + selfRoleTable = new SelfRoleTable(this); + } + + public SelfRoleTable getSelfRoleData(){ + return selfRoleTable; + } + + protected Connection connect() throws SQLException { + return connection.connect(); + } + +} diff --git a/src/main/java/net/tylermurphy/ken/database/SelfRoleTable.java b/src/main/java/net/tylermurphy/ken/database/SelfRoleTable.java new file mode 100644 index 0000000..d4c2a92 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/SelfRoleTable.java @@ -0,0 +1,56 @@ +package net.tylermurphy.ken.database; + +import net.tylermurphy.ken.Ken; + +import java.sql.*; + +public class SelfRoleTable { + + private final Database database; + + public SelfRoleTable(Database database){ + + String sql = "CREATE TABLE IF NOT EXISTS self_role_data (\n" + + " guild_id BIGINT NOT NULL,\n" + + " page INT NOT NULL,\n" + + " data TEXT NOT NULL," + + " PRIMARY KEY (guild_id,page)\n" + + ");"; + + try(Connection connection = database.connect(); Statement statement = connection.createStatement()) { + statement.executeUpdate(sql); + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + } + + this.database = database; + } + + public String getData(long guildId, int page){ + String sql = "SELECT * FROM self_role_data WHERE guild_id=? AND page=?"; + try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, guildId); + statement.setInt(2, page); + ResultSet rs = statement.executeQuery(); + if(rs.next()) return rs.getString("data"); + else return null; + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + return null; + } + } + + public boolean setData(long guildId, int page, String data){ + String sql = "INSERT OR REPLACE INTO self_role_data (guild_id, page, data) VALUES(?,?,?)"; + try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) { + statement.setLong(1, guildId); + statement.setInt(2, page); + statement.setString(3, data); + return statement.executeUpdate() != 0; + } catch (SQLException e) { + Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage()); + return false; + } + } + +} diff --git a/src/main/java/net/tylermurphy/ken/database/connections/DatabaseConnection.java b/src/main/java/net/tylermurphy/ken/database/connections/DatabaseConnection.java new file mode 100644 index 0000000..c306886 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/connections/DatabaseConnection.java @@ -0,0 +1,10 @@ +package net.tylermurphy.ken.database.connections; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface DatabaseConnection { + + Connection connect() throws SQLException; + +} \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/database/connections/MySQLConnection.java b/src/main/java/net/tylermurphy/ken/database/connections/MySQLConnection.java new file mode 100644 index 0000000..4fb7fce --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/connections/MySQLConnection.java @@ -0,0 +1,43 @@ +package net.tylermurphy.ken.database.connections; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import net.tylermurphy.ken.Ken; + +import java.sql.Connection; +import java.sql.SQLException; + +public class MySQLConnection implements DatabaseConnection { + + private final HikariDataSource ds; + + public MySQLConnection(){ + + HikariConfig config = new HikariConfig(); + + String host = Ken.getInstance().getConfig().getString("database.host"); + String port = Ken.getInstance().getConfig().getString("database.port"); + String username = Ken.getInstance().getConfig().getString("database.username"); + String password = Ken.getInstance().getConfig().getString("database.password"); + String databaseName = Ken.getInstance().getConfig().getString("database.databaseName"); + + config.setJdbcUrl("jdbc:mariadb://"+host+":"+port+"/"+databaseName); + config.addDataSourceProperty("cachePrepStmts", "true"); + config.addDataSourceProperty("prepStmtCacheSize", "250"); + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + config.addDataSourceProperty("user", username); + config.addDataSourceProperty("password",password); + config.addDataSourceProperty("autoCommit", "true"); + config.setAutoCommit(true); + config.setMaximumPoolSize(20); + + ds = new HikariDataSource(config); + + } + + @Override + public Connection connect() throws SQLException { + return ds.getConnection(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/tylermurphy/ken/database/connections/SQLiteConnection.java b/src/main/java/net/tylermurphy/ken/database/connections/SQLiteConnection.java new file mode 100644 index 0000000..48f0b83 --- /dev/null +++ b/src/main/java/net/tylermurphy/ken/database/connections/SQLiteConnection.java @@ -0,0 +1,46 @@ +package net.tylermurphy.ken.database.connections; + + +import net.tylermurphy.ken.Ken; +import org.sqlite.SQLiteConfig; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SQLiteConnection implements DatabaseConnection { + + private final File databaseFile; + private final SQLiteConfig config; + + public SQLiteConnection(){ + + try { + Class.forName("org.sqlite.JDBC"); + } catch (ClassNotFoundException e) { + Ken.getInstance().getLogger().error(e.getMessage()); + throw new RuntimeException(e.getMessage()); + } + + databaseFile = new File(Ken.getInstance().getConfigFolder(), "database.db"); + + config = new SQLiteConfig(); + config.setSynchronous(SQLiteConfig.SynchronousMode.NORMAL); + config.setTempStore(SQLiteConfig.TempStore.MEMORY); + } + + @Override + public Connection connect() { + Connection conn = null; + try { + String url = "jdbc:sqlite:"+databaseFile; + conn = DriverManager.getConnection(url, config.toProperties()); + } catch (SQLException e) { + Ken.getInstance().getLogger().error(e.getMessage()); + e.printStackTrace(); + } + return conn; + } + +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 32c69ce..f050e38 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -13,14 +13,17 @@ # Example: "N1q2O3E4NzgyNRGHjk#zFTgy.G7Qb2Z.Hr36Qj5p3P56GueIFxVQOAAEre22DXB4u56FX11c" botToken: "" -# This is the information used to connect to a MySQL compatible database. A database is REQUIRED -# for KenBotReborn to function. +# This is the information used to connect to a MySQL compatible database. A database is recommended +# for KenBotReborn to function. You can use a sqlite database instead, but its highly discoursed. +# If you want to use MySQL, put your database connection information below, if you want to use sqlite, +# set database.sqlite to true, and every other option will be ignored. database: host: "127.0.0.1" port: "3306" username: "root" password: "admin" databaseName: "database" + sqlite: false # If you want the ability for KenBotReborn to play music from YouTube in a voice channel, then # you need access to the YoutubeAPI. Get a YouTube API key from the Google Developer Console and