diff --git a/.gitignore b/.gitignore index 3bd3447..a213d79 100644 --- a/.gitignore +++ b/.gitignore @@ -194,4 +194,5 @@ gradle-app.setting rsc/* !rsc/Ordnerstruktur.txt -!rsc/tts.py \ No newline at end of file +!rsc/tts.py +!rsc/sauceConfig.json \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index cd8449f..7df28e5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,9 @@ dependencies { implementation 'com.sedmelluq:lavaplayer:1.3.73' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.0' + + compileOnly 'org.projectlombok:lombok:1.18.16' + annotationProcessor 'org.projectlombok:lombok:1.18.16' } mainClassName = 'de.yannicpunktdee.yoshibot.main.Main' diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommandContext.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommandContext.java index 53ddd55..171f825 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommandContext.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommandContext.java @@ -3,13 +3,6 @@ package de.yannicpunktdee.yoshibot.command; import java.util.*; import de.yannicpunktdee.yoshibot.command.YoshiCommandDistributor.Action; -import de.yannicpunktdee.yoshibot.command.commands.SauceCommand; -import de.yannicpunktdee.yoshibot.main.SauceProvider; -import de.yannicpunktdee.yoshibot.main.YoshiBot; -import net.dv8tion.jda.api.entities.Guild; -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.events.message.MessageReceivedEvent;; /** diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/ListCommand.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/ListCommand.java index 58b5a8b..d9691dc 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/ListCommand.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/ListCommand.java @@ -2,7 +2,7 @@ package de.yannicpunktdee.yoshibot.command.commands; import de.yannicpunktdee.yoshibot.command.YoshiCommand; import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; -import de.yannicpunktdee.yoshibot.main.Resources; +import de.yannicpunktdee.yoshibot.utils.Resources; import net.dv8tion.jda.api.EmbedBuilder; import java.awt.*; diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/PlayCommand.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/PlayCommand.java index 567a56f..5b42ece 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/PlayCommand.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/PlayCommand.java @@ -6,7 +6,7 @@ import de.yannicpunktdee.yoshibot.audio.AudioController; import de.yannicpunktdee.yoshibot.audio.AudioLoadResultHandlerImpl; import de.yannicpunktdee.yoshibot.command.YoshiCommand; import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; -import de.yannicpunktdee.yoshibot.main.Resources; +import de.yannicpunktdee.yoshibot.utils.Resources; import de.yannicpunktdee.yoshibot.main.YoshiBot; import net.dv8tion.jda.api.entities.VoiceChannel; diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SauceCommand.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SauceCommand.java index 84131de..4ee8195 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SauceCommand.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SauceCommand.java @@ -2,7 +2,7 @@ package de.yannicpunktdee.yoshibot.command.commands; import de.yannicpunktdee.yoshibot.command.YoshiCommand; import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; -import de.yannicpunktdee.yoshibot.main.SauceProvider; +import de.yannicpunktdee.yoshibot.utils.SauceProvider; import net.dv8tion.jda.api.entities.MessageEmbed; import java.util.Arrays; diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SayCommand.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SayCommand.java index aea9213..d43baf5 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SayCommand.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/commands/SayCommand.java @@ -4,7 +4,7 @@ import de.yannicpunktdee.yoshibot.audio.AudioController; import de.yannicpunktdee.yoshibot.audio.AudioLoadResultHandlerImpl; import de.yannicpunktdee.yoshibot.command.YoshiCommand; import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; -import de.yannicpunktdee.yoshibot.main.Resources; +import de.yannicpunktdee.yoshibot.utils.Resources; import de.yannicpunktdee.yoshibot.main.YoshiBot; import de.yannicpunktdee.yoshibot.utils.Logger; import net.dv8tion.jda.api.entities.VoiceChannel; @@ -45,7 +45,7 @@ public class SayCommand extends YoshiCommand { try { ProcessBuilder pb = new ProcessBuilder( "python3", - "rsc/tts.py", + Resources.getTts_path(), "--text", context.getArgument("text"), "--lang", diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/listeners/CommandListener.java b/app/src/main/java/de/yannicpunktdee/yoshibot/listeners/CommandListener.java index 7ea1e01..cade680 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/listeners/CommandListener.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/listeners/CommandListener.java @@ -1,7 +1,7 @@ package de.yannicpunktdee.yoshibot.listeners; import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; -import de.yannicpunktdee.yoshibot.main.Resources; +import de.yannicpunktdee.yoshibot.utils.Resources; import de.yannicpunktdee.yoshibot.main.YoshiBot; import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java b/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java index 2649688..267725e 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java @@ -12,6 +12,8 @@ import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; import de.yannicpunktdee.yoshibot.command.YoshiCommandDistributor; import de.yannicpunktdee.yoshibot.listeners.CommandLine; import de.yannicpunktdee.yoshibot.listeners.CommandListener; +import de.yannicpunktdee.yoshibot.utils.Resources; +import de.yannicpunktdee.yoshibot.utils.SauceProvider; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.OnlineStatus; diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Logger.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Logger.java index 4cb184d..9c6bf1b 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Logger.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Logger.java @@ -1,21 +1,20 @@ package de.yannicpunktdee.yoshibot.utils; -public class Logger { - - public static enum Type { - INFO, - WARNING, - ERROR - } - - - public static void log(String message, Type type){ - StringBuilder sb = new StringBuilder(); - sb.append("[Yoshi::"); - sb.append(((type == null)? Type.INFO : type).toString()); - sb.append("] "); - sb.append(message); - System.out.println(sb.toString()); - } - +public final class Logger { + + public enum Type { + INFO, + WARNING, + ERROR + } + + + public static void log(String message, Type type) { + String text = String.format("[%tT: Yoshi::%s] %s", + System.currentTimeMillis(), + (type == null ? Type.INFO : type), + message); + System.out.println(text); + } + } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/main/Resources.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java similarity index 68% rename from app/src/main/java/de/yannicpunktdee/yoshibot/main/Resources.java rename to app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java index 9bd6fd6..cdb2909 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/Resources.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java @@ -1,15 +1,18 @@ -package de.yannicpunktdee.yoshibot.main; +package de.yannicpunktdee.yoshibot.utils; -import de.yannicpunktdee.yoshibot.utils.Logger; import de.yannicpunktdee.yoshibot.utils.Logger.Type; +import lombok.Getter; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; import java.util.*; -import java.util.stream.Collectors; +import java.util.stream.StreamSupport; -public class Resources { +public final class Resources { private static final String default_propertiesFilePath = "rsc/Config.properties"; private static String propertiesFilePath = default_propertiesFilePath; @@ -22,14 +25,22 @@ public class Resources { private static final String[] default_restrict_commands_to_channel = null; private static String[] restrict_commands_to_channel = default_restrict_commands_to_channel; - - private static String[] filtered_tags; - private static Map> feedDetails; - + @Getter + private static String[] filteredTags; + @Getter + private static final Map> feedDetails = new HashMap<>(); + + @Getter + private static String tts_path; + + @Getter + private static String sauceConfigPath; + + public synchronized static boolean init(String pathToConfig) { Logger.log("Lade Config.properties ...", Type.INFO); - + if (pathToConfig != null) { if (!(new File(pathToConfig)).exists()) { Logger.log("Der in den Argumenten angegebene Pfad zur Config.properties existiert nicht.", Type.ERROR); @@ -41,26 +52,31 @@ public class Resources { Type.ERROR); return false; } - + propertiesFile = new Properties(); try { propertiesFile.load( new FileInputStream(propertiesFilePath) - ); + ); Logger.log("Config-Datei erfolgreich geladen.", Type.INFO); } catch (IOException e) { Logger.log("Es ist ein Fehler beim Öffnen der Config.propeties aufgetreten.", Type.ERROR); return false; } - + + tts_path = propertiesFile.getProperty("path_to_tts"); + sauceConfigPath = propertiesFile.getProperty("path_to_sauce_config"); + boolean isOk = initJdaBuilderString(); if (isOk) isOk = initChannelRestrict(); if (isOk) isOk = initAudio(); initTagFilter(); + + if (isOk) Logger.log("Die Konfigurationen wurden erfolgreich geladen.", Type.INFO); else Logger.log("Die Konfiguration konnte nicht geladen werden", Type.ERROR); - + return isOk; } @@ -72,60 +88,75 @@ public class Resources { jda_builder_string = propertiesFile.getProperty("jda_builder_string"); return true; } - + public static String getJdaBuilderString() { return jda_builder_string; } - + private static void initTagFilter() { - if (!propertiesFile.containsKey("tags_general_filter")) { - Logger.log("Kein Attribut 'tags_general_filter' gefunden", Type.WARNING); - } else { - filtered_tags = propertiesFile.getProperty("tags_general_filter").split(" "); - } - if (!propertiesFile.containsKey("feed_positive_tags")) { - Logger.log("Kein Attribut 'feed_positive_tags' gefunden", Type.WARNING); - } else { - String[] automatedFeeds = propertiesFile.getProperty("feed_positive_tags").split("//"); - feedDetails = Arrays.stream(automatedFeeds).map(feedDetail -> feedDetail.split(" ")) - .collect(Collectors.toMap(list -> list[0], - list -> Arrays.asList(list).subList(1, list.length))); + try { + JSONObject configBase = new JSONObject( + String.join("\n", + Files.readAllLines(new File(sauceConfigPath).toPath()))); + JSONArray filter = configBase.getJSONArray("tags_general_filter"); + filteredTags = + StreamSupport.stream(filter.spliterator(), false).map(i -> (String) i).toArray(String[]::new); + JSONArray feeds = configBase.getJSONArray("feeds"); + for (Object feedConfigObj : feeds) { + JSONObject feedConfig = (JSONObject) feedConfigObj; + List tags = new ArrayList<>(); + for (Object tagObj : feedConfig.getJSONArray("tags")) { + if (tagObj instanceof String) { + tags.add((String) tagObj); + } else if (tagObj instanceof JSONArray) { + StringBuilder sb = new StringBuilder().append("(%20"); + sb.append(((JSONArray) tagObj).join("%20~%20")); + tags.add(sb.append("%20)").toString()); + } + } + feedDetails.put(feedConfig.getString("channel"), tags); + } + } catch (IOException e) { + e.printStackTrace(); } } - + private static boolean initAudio() { if (propertiesFile.containsKey("audio_source_directory")) { audio_source_directory = propertiesFile.getProperty("audio_source_directory"); } else { Logger.log("Die Config.properties spezifiziert kein audio_source_directory. Lade default.", Type.WARNING); } - + File file = new File(audio_source_directory); if (!file.exists() || !file.isDirectory()) { Logger.log("Das Audio-Verzeichnis wurde nicht gefunden.", Type.ERROR); return false; } - + if (file.listFiles().length < 1) Logger.log("Das Audio-Verzeichnis ist leer.", Type.WARNING); - + return true; } - + public static String getAudioFilePath(String name) { name = audio_source_directory + (audio_source_directory.endsWith("/") ? "" : "/") + name + ".opus"; if ((new File(name)).exists()) return name; else return null; } + public static String getTempAudioFilePath(String name) { - name = audio_source_directory + (audio_source_directory.endsWith("/")? "" : "/") + "temp/" + name + ".opus"; - if((new File(name)).exists()) return name; + name = audio_source_directory + (audio_source_directory.endsWith("/") ? "" : "/") + "temp/" + name + ".opus"; + if ((new File(name)).exists()) return name; else return null; } - public static String buildTempAudioFilePath(String name){ + + public static String buildTempAudioFilePath(String name) { return System.getProperty("java.io.tmpdir") + "/yoshibot/" + name; } + public static String getAudioSourceDirectory() { return audio_source_directory; } @@ -135,17 +166,10 @@ public class Resources { restrict_commands_to_channel = propertiesFile.getProperty("restrict_commands_to_channel").split(" "); return true; } - + public static String[] getRestrictCommandsToChannel() { return restrict_commands_to_channel; } - - public static Map> getFeedDetails() { - return feedDetails; - } - - public static String[] getGeneralFilterTags() { - return filtered_tags; - } - + + } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/main/SauceProvider.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java similarity index 82% rename from app/src/main/java/de/yannicpunktdee/yoshibot/main/SauceProvider.java rename to app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java index 1b310e0..e61f467 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/SauceProvider.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java @@ -1,7 +1,6 @@ -package de.yannicpunktdee.yoshibot.main; +package de.yannicpunktdee.yoshibot.utils; -import de.yannicpunktdee.yoshibot.utils.Logger; -import de.yannicpunktdee.yoshibot.utils.RestHelper; +import de.yannicpunktdee.yoshibot.main.YoshiBot; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.TextChannel; @@ -42,7 +41,7 @@ public class SauceProvider { public static MessageEmbed getSauce(int index) { String url = BASE_URL + "posts?id=" + index; JSONObject base = getParsedSauceData(url); - if (base.getInt("count") == 0){ + if (base.getInt("count") == 0) { return getNotFoundEmbed(); } JSONObject post = base.getJSONArray("posts").getJSONObject(0); @@ -51,12 +50,13 @@ public class SauceProvider { public static MessageEmbed getRandomSauce(String tags) { tags = tagsForRest(tags); - tags += "+" + String.join("+", Resources.getGeneralFilterTags()); + tags += "+" + String.join("+", Resources.getFilteredTags()); Random rand = new Random(); String url = BASE_URL + "posts?tags=" + String.join("+", tags); + Logger.log("Soße angefordert für tags " + tags, Logger.Type.INFO); JSONObject baseObj = getParsedSauceData(url); int amount = baseObj.getInt("count"); - if (amount == 0){ + if (amount == 0) { return getNotFoundEmbed(); } int selectedIndex = rand.nextInt(amount); @@ -83,7 +83,7 @@ public class SauceProvider { if (!isSauceInit) return; for (Map.Entry> feed : Resources.getFeedDetails().entrySet()) { String url = BASE_URL + "posts?tags=" + String.join("+", feed.getValue()) - + "+" + String.join("+", Resources.getGeneralFilterTags()); + + "+" + String.join("+", Resources.getFilteredTags()); JSONArray posts = getParsedSauceData(url).getJSONArray("posts"); assert posts != null; List postsInternal = @@ -104,8 +104,11 @@ public class SauceProvider { } channels.get(0).sendMessage(makeStringFromJson(post)).queue(); } - Logger.log(String.format("Found %d posts for feed '%s'", postsInternal.size(), feed.getKey()), - Logger.Type.INFO); + if (postsInternal.size() > 0) { + Logger.log(String.format("Found %d posts for feed '%s'", postsInternal.size(), feed.getKey()), + Logger.Type.INFO); + } + } lastKnownSauce = this.getNewestIndex(); } @@ -121,7 +124,6 @@ public class SauceProvider { List channels = yoshiBot.jda.getTextChannelsByName(entry.getKey(), true); if (channels.size() > 0) { this.isSauceInit = true; - this.provideSauce(); } else { Logger.log("Konnte keine Kanaäle finden für die Soße", Logger.Type.ERROR); } @@ -130,37 +132,29 @@ public class SauceProvider { private int getNewestIndex() { JSONObject result = getParsedSauceData("https://r34-json.herokuapp.com/posts?limit=1&q=index"); + assert result != null; return result.getJSONArray("posts").getJSONObject(0).getInt("id"); } private static JSONObject getParsedSauceData(String url) { - String raw = null; try { raw = RestHelper.getFromURL(url); + assert raw != null; + return new JSONObject(raw); } catch (IOException e) { e.printStackTrace(); } - assert raw != null; - return new JSONObject(raw); + return null; } private static String tagsForRest(String tags) { - char[] chars = tags.toCharArray(); - for (int i = 1; i < chars.length - 1; i++) { - if (chars[i] == ' ') { - if (chars[i - 1] != '(' && chars[i + 1] != ')' && chars[i - 1] != '~' && chars[i + 1] != '~') { - chars[i] = '\t'; - } - } - } - String result = new String(chars); - result = result.replace(" ", "%20").replace("\t", "+"); - return result; + tags = tags.replace(" ", "+"); + return tags; } - private static MessageEmbed getNotFoundEmbed(){ - if (SauceProvider.notFoundEmbed == null){ + private static MessageEmbed getNotFoundEmbed() { + if (SauceProvider.notFoundEmbed == null) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("Could not find any posts matching the filter!"); SauceProvider.notFoundEmbed = eb.build(); diff --git a/rsc/sauceConfig.json b/rsc/sauceConfig.json new file mode 100644 index 0000000..f043fad --- /dev/null +++ b/rsc/sauceConfig.json @@ -0,0 +1,53 @@ +{ + "tags_general_filter": [ + "-anthro", + "-nonconsensual", + "-rape", + "-vore", + "-scat", + "-yiff", + "-snuff", + "-crossdressing", + "-mind_break" + ], + "feeds": [ + { + "channel": "snek-feed", + "tags": [ + "lamia", + [ + "breasts", + "*girl*" + ] + ] + }, + { + "channel": "auto-feed", + "tags": [ + [ + "fire_emblem", + "samus_aran", + "metroid", + "palutena", + "xenoblade_chronicles", + "xenoblade_chronicles_2", + "nintendo", + "star_wars", + "nier:_automata", + "monster_girl", + "tate_no_yuusha_no_nariagari", + "zero_two_(darling_in_the_franxx)", + "re:zero_kara_hajimeru_isekai_seikatsu", + "fate_(series)", + "darling_in_the_franxx", + "dungeon_ni_deai_wo_motomeru_no_wa_machigatteiru_darou_ka", + "touhou" + ], + [ + "breasts", + "*girl*" + ] + ] + } + ] +} \ No newline at end of file