diff --git a/app/build.gradle b/app/build.gradle index 7df28e5..5b8b1b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,15 +22,17 @@ dependencies { // This dependency is used by the application. implementation 'com.google.guava:guava:29.0-jre' - - implementation group: 'org.json', name: 'json', version: '20210307' - - implementation 'net.dv8tion:JDA:4.2.0_247' - - implementation 'com.sedmelluq:lavaplayer:1.3.73' + + implementation group: 'org.json', name: 'json', version: '20210307' + + implementation 'net.dv8tion:JDA:4.2.0_247' + + implementation 'com.sedmelluq:lavaplayer:1.3.73' implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.0' + implementation "net.dean.jraw:JRAW:1.1.0" + compileOnly 'org.projectlombok:lombok:1.18.16' annotationProcessor 'org.projectlombok:lombok:1.18.16' } @@ -42,11 +44,11 @@ application { mainClass = "$mainClassName" } -jar{ - manifest{ +jar { + manifest { attributes "Main-Class": "$mainClassName" } from { - configurations.runtimeClasspath.findAll({!it.path.endsWith(".pom")}).collect { it.isDirectory() ? it : zipTree(it) } + configurations.runtimeClasspath.findAll({ !it.path.endsWith(".pom") }).collect { it.isDirectory() ? it : zipTree(it) } } } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommand.java b/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommand.java index 626951c..930b0f8 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommand.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/command/YoshiCommand.java @@ -3,6 +3,7 @@ package de.yannicpunktdee.yoshibot.command; import de.yannicpunktdee.yoshibot.main.YoshiBot; import de.yannicpunktdee.yoshibot.utils.Logger; import de.yannicpunktdee.yoshibot.utils.Resources; +import lombok.NonNull; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Message.Attachment; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -55,26 +56,29 @@ public abstract class YoshiCommand { } return true; } - - protected final void sendMessage(String message){ + + protected final void sendMessage(String message) { EmbedBuilder eb = new EmbedBuilder(); eb.setColor(Color.pink); eb.setDescription(message); context.getEvent().getTextChannel().sendMessage(eb.build()).queue(); } - protected final void sendFile(File file, String description){ + + protected final void sendFile(File file, String description) { EmbedBuilder eb = new EmbedBuilder(); eb.setColor(Color.pink); - if(description != null) eb.setDescription(description); + if (description != null) eb.setDescription(description); context.getEvent().getTextChannel().sendFile(file).queue(); } - protected final void sendInfoMessage(String message){ + + protected final void sendInfoMessage(String message) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("INFO"); eb.setColor(Color.blue); eb.setDescription(message); context.getEvent().getTextChannel().sendMessage(eb.build()).queue(); } + protected final void sendErrorMessage(String message) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("ERROR"); @@ -82,10 +86,11 @@ public abstract class YoshiCommand { eb.setDescription(message); context.getEvent().getTextChannel().sendMessage(eb.build()).queue(); } + protected final void sendCustomMessage(MessageEmbed messageEmbed) { context.getEvent().getTextChannel().sendMessage(messageEmbed).queue(); } - + protected File downloadAttachmentToFile(String directoryPath, String name) { if (directoryPath == null) directoryPath = Resources.getTempPath(); @@ -122,23 +127,25 @@ public abstract class YoshiCommand { return file; } - - protected VoiceChannel getVoiceChannelByParam(){ + + protected VoiceChannel getVoiceChannelByParam() { VoiceChannel vc; - if(context.containsArguments(new String[]{"channel"})){ - if(context.getArgument("channel") == null) return null; - List channels = YoshiBot.getInstance().jda.getVoiceChannelsByName(context.getArgument("channel"), true); + if (context.containsArguments(new String[]{"channel"})) { + if (context.getArgument("channel") == null) return null; + List channels = YoshiBot.getInstance().jda + .getVoiceChannelsByName(context.getArgument("channel"), true); if (!(channels.size() > 0)) { sendErrorMessage("Der Kanalname konnte nicht gefunden werden."); return null; } vc = channels.get(0); - }else { - try{ + } else { + try { vc = context.getEvent().getMember().getVoiceState().getChannel(); - if(vc == null) vc = YoshiBot.getInstance().getGuild().getAudioManager().getConnectedChannel(); - }catch (Exception e){ - sendErrorMessage("Es konnte kein Voicekanal gefunden werden in dem die Audio-Datei abgespielt werden kann."); + if (vc == null) vc = YoshiBot.getInstance().getGuild().getAudioManager().getConnectedChannel(); + } catch (Exception e) { + sendErrorMessage( + "Es konnte kein Voicekanal gefunden werden in dem die Audio-Datei abgespielt werden kann."); return null; } } 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 b4e4e31..97ac423 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 @@ -29,20 +29,21 @@ public class SauceCommand extends YoshiCommand { sendErrorMessage("Dieser Kanal is nix gut, weil vong nsfw her. Geh woanders hin du kek"); return true; } - List arguments = Arrays.asList(context.getArgument("tags").split(" ")); - try { - arguments.stream().map(Integer::parseInt).map(this::byIndex).forEach(this::sendCustomMessage); - } catch (Exception e) { - sendCustomMessage(byTags(arguments)); + if (context.getArgument("tags") != null) { + sendCustomMessage(byTags(Arrays.asList(context.getArgument("tags").split(" ")))); + return true; + } else if (context.getArgument("id") != null) { + sendCustomMessage(byIndex(Integer.parseInt(context.getArgument("id")))); + return true; } - return true; + return false; } private MessageEmbed byIndex(int index) { return SauceProvider.getSauce(index); } - private MessageEmbed byTags(List tags){ + private MessageEmbed byTags(List tags) { return SauceProvider.getRandomSauce(String.join(" ", tags)); } } diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/main/Main.java b/app/src/main/java/de/yannicpunktdee/yoshibot/main/Main.java index 46ab83c..971c54e 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/Main.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/main/Main.java @@ -7,30 +7,30 @@ import java.net.URISyntaxException; /** * Main-Klasse und Startpunkt für die Bot-Applikation. + * * @author Yannic Link */ public class Main { /** * Eintrittspunkt für die Applikation. Erzeugen eines neuen Yoshi-Bots und Starten. + * * @param args Aufrufargumente. Werden später zum Konfigurieren genutzt. - * @throws URISyntaxException + * + * @throws URISyntaxException */ public static void main(String[] args) throws URISyntaxException { YoshiBot yoshiBot = YoshiBot.getInstance(); - if(!yoshiBot.init((args.length > 0)? args[0] : null)){ + if (!yoshiBot.init((args.length > 0) ? args[0] : null)) { Logger.logError("Es ist ein Fehler beim Initialisieren der Ressourcen aufgetreten."); return; } - + Logger.logInfo("Ressourcen erfolgreich initialisiert. Starte Yoshi Bot ..."); - try { - yoshiBot.start(); - }catch(LoginException e) { - System.err.println("Es ist ein Fehler beim Login aufgetreten."); - } + + yoshiBot.start(); } - + } 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 ff0347c..6dc0642 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/main/YoshiBot.java @@ -81,11 +81,9 @@ public final class YoshiBot { /** * Startet den Bot und schaltet ihn online. Beginnt auf Konsoleneingaben für administrative Zwecke zu lauschen. - * - * @throws LoginException Falls das Token ungültig ist. - */ + **/ @SneakyThrows - public void start() throws LoginException { + public void start() { System.out.println("Starte YoshiBot."); jdaBuilder = JDABuilder.createDefault(Resources.getJda_builder_string()); @@ -119,7 +117,9 @@ public final class YoshiBot { commandLineThread = new CommandLine(); commandLineThread.start(); - new SauceProvider(300); + SauceProvider.init(300); + + //RedditProvider.init(); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(YoshiBot::setRandomActivity, 0, 10, TimeUnit.HOURS); @@ -160,8 +160,8 @@ public final class YoshiBot { Logger.logInfo("Setze Aktivität auf " + activity); } - public synchronized void joinVoiceChannel(VoiceChannel vc){ - if(vc == null) { + public synchronized void joinVoiceChannel(VoiceChannel vc) { + if (vc == null) { guild.getAudioManager().closeAudioConnection(); return; } @@ -174,24 +174,23 @@ public final class YoshiBot { } } - public void joinVoiceChannelWithMostMembers(){ + public void joinVoiceChannelWithMostMembers() { VoiceChannel maxVoiceChannel = null; int maxMembers = 0; - for(VoiceChannel vc : guild.getVoiceChannels()){ + for (VoiceChannel vc : guild.getVoiceChannels()) { int membersInChannel = 0; - for(Member m : vc.getMembers()) - if(!m.getUser().isBot()) membersInChannel++; - if(membersInChannel > maxMembers){ + for (Member m : vc.getMembers()) + if (!m.getUser().isBot()) membersInChannel++; + if (membersInChannel > maxMembers) { maxVoiceChannel = vc; - maxMembers = membersInChannel; + maxMembers = membersInChannel; } } - if(maxMembers < 1) joinVoiceChannel(null); - else if(maxMembers > 0 && maxVoiceChannel != null) - joinVoiceChannel(maxVoiceChannel); + if (maxMembers < 1) joinVoiceChannel(null); + else joinVoiceChannel(maxVoiceChannel); } - public boolean playSound(File file, VoiceChannel vc){ + public boolean playSound(File file, VoiceChannel vc) { if (!file.isFile()) return false; joinVoiceChannel(vc); diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/RedditProvider.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/RedditProvider.java new file mode 100644 index 0000000..948ab51 --- /dev/null +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/RedditProvider.java @@ -0,0 +1,38 @@ +package de.yannicpunktdee.yoshibot.utils; + +import lombok.Getter; +import net.dean.jraw.RedditClient; +import net.dean.jraw.http.NetworkAdapter; +import net.dean.jraw.http.OkHttpNetworkAdapter; +import net.dean.jraw.http.UserAgent; +import net.dean.jraw.oauth.Credentials; +import net.dean.jraw.oauth.OAuthHelper; + +public final class RedditProvider { + + @Getter + private static boolean isInit = false; + + private static RedditClient reddit; + + public static void init() { + if (isInit) Logger.logWarning("RedditProvider wird reinitialisiert"); + + String username = Resources.getRedditData().get("username"); + String password = Resources.getRedditData().get("password"); + String clientId = Resources.getRedditData().get("client_id"); + String clientSecret = Resources.getRedditData().get("client_secret"); + + UserAgent userAgent = new UserAgent("bot", "de.yannicpunktdee.yoshibot", "v1", username); + + + Credentials creds = Credentials.script(username, password, clientId, clientSecret); + + NetworkAdapter adapter = new OkHttpNetworkAdapter(userAgent); + + reddit = OAuthHelper.automatic(adapter, creds); + + isInit = true; + } + +} diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java index 49a6785..6b25dca 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/Resources.java @@ -13,6 +13,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.StreamSupport; public final class Resources { @@ -23,7 +24,7 @@ public final class Resources { private static String configPath; @Getter private static String audioPath; - + private static String tempPath; @Getter private static String activitiesPath; @@ -45,6 +46,9 @@ public final class Resources { @Getter private static String jda_builder_string; + @Getter + private static Map redditData; + @Getter private static Long guild_id; @@ -62,6 +66,7 @@ public final class Resources { private static final Map> feedDetails = new HashMap<>(); private static Properties propertiesFile; + private static Properties redditCreds; public synchronized static boolean init(String resourcePathArg) { @@ -80,6 +85,7 @@ public final class Resources { if (isOk) isOk = initPatPngPath(); if (isOk) isOk = initImages(); if (isOk) isOk = initBonkPngPath(); + if (isOk) isOk = initReddit(); if (isOk) Logger.logInfo("Die Konfigurationen wurden erfolgreich geladen."); else Logger.logError("Die Konfiguration konnte nicht geladen werden"); @@ -107,6 +113,9 @@ public final class Resources { propertiesFile = new Properties(); propertiesFile.load(new FileInputStream(configPath)); + redditCreds = new Properties(); + redditCreds.load(new FileInputStream(resourcePath + "RedditCredentials.properties")); + return true; } @@ -137,14 +146,23 @@ public final class Resources { return false; } } - - public static String getTempPath(){ + + public static String getTempPath() { + if (tempPath == null){ + initTemp(); + } File tempDir = new File(tempPath); - if(!tempDir.isDirectory()) - if(!tempDir.mkdir()) return null; + if (!tempDir.isDirectory()) + if (!tempDir.mkdir()) throw new Error("Could not make Temp directory"); return tempPath; } + private static boolean initReddit() { + redditData = redditCreds.stringPropertyNames().stream() + .collect(Collectors.toMap(p -> p, property -> redditCreds.getProperty(property))); + return true; + } + private static boolean initActivities() { activitiesPath = verifyExists(resourcePath + "activities.txt", File::isFile); return activitiesPath != null; @@ -174,7 +192,7 @@ public final class Resources { patPngPath = verifyExists(resourcePath + "pats/", File::isDirectory); return patPngPath != null; } - + private static boolean initBonkPngPath() { bonkPngPath = verifyExists(resourcePath + "bonks/", File::isDirectory); return bonkPngPath != null; @@ -282,7 +300,7 @@ public final class Resources { private static String verifyExists(String filename, Function checkIsValidFile) { String[] split = filename.split("/"); - Logger.logInfo(String.format("Versuche %s zu finden.", split[split.length - 1])); + Logger.logDebug(String.format("Versuche %s zu finden.", split[split.length - 1])); if (checkIsValidFile.apply(new File(filename))) { return filename; } else { diff --git a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java index 8f12d7e..b217e9a 100644 --- a/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java +++ b/app/src/main/java/de/yannicpunktdee/yoshibot/utils/SauceProvider.java @@ -14,26 +14,36 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.StreamSupport; -public class SauceProvider { +public final class SauceProvider { private static final String BASE_URL = "https://r34-json.herokuapp.com/"; - private int lastKnownSauce = -1; + private static int lastKnownSauce = -1; - private boolean isSauceInit = false; + private static boolean isSauceInit = false; private static MessageEmbed notFoundEmbed = null; - public SauceProvider(int timer) { - lastKnownSauce = this.getNewestIndex(); - ScheduledExecutorService sauceScheduler = Executors.newScheduledThreadPool(4); - sauceScheduler.scheduleAtFixedRate(this::provideSauce, 0, timer, TimeUnit.SECONDS); - new Thread(this::initSauceProviding).start(); + private static final ScheduledExecutorService sauceScheduler = Executors.newScheduledThreadPool(1); + + public static void init(int secondsPerTime) { + init(secondsPerTime, TimeUnit.SECONDS); + } + + public static void init(int timer, TimeUnit timeUnit) { + init(timer, timeUnit, getNewestIndex()); } - public SauceProvider(int timer, int lastKnownSauce) { - this(timer); - this.lastKnownSauce = lastKnownSauce; + public static void init(int timer, TimeUnit timeUnit, int lastKnownSauce) { + sauceScheduler.scheduleAtFixedRate(() -> { + try { + SauceProvider.provideSauce(); + } catch (Exception e) { + e.printStackTrace(); + } + }, 0, timer, timeUnit); + SauceProvider.lastKnownSauce = lastKnownSauce; + new Thread(SauceProvider::initSauceProviding).start(); } public static MessageEmbed getSauce(int index) { @@ -69,15 +79,27 @@ public class SauceProvider { private static MessageEmbed makeStringFromJson(JSONObject post) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("Soße").setDescription("URL: " + post.getString("file_url").substring(42)); + String tags = "`" + post.getJSONArray("tags").join("` `") + "`"; + if (tags.length() > 1024) { + List tagParts = new ArrayList<>(); + while (tags.length() > 1024) { + int lastindexoftag = tags.substring(0, 1024).lastIndexOf(' '); + tagParts.add(tags.substring(0, lastindexoftag)); + tags = tags.substring(lastindexoftag + 1); + } + tagParts.add(tags); + tagParts.forEach(tagPart -> eb.addField("Tags:", tagPart, false)); + } else { + eb.addField("Tags", tags, false); + } eb.addField("ID", post.getString("id"), false); - eb.addField("Tags", "`" + post.getJSONArray("tags").join("` `") + "`", false); eb.setImage(post.getString("file_url").substring(42)); return eb.build(); } - private void provideSauce() { - if (!isSauceInit) return; + private static void provideSauce() { + if (!isSauceInit || lastKnownSauce < 0) return; for (Map.Entry> feed : Resources.getFeedDetails().entrySet()) { String url = BASE_URL + "posts?tags=" + String.join("+", feed.getValue()) + "+" + String.join("+", Resources.getFilteredTags()); @@ -106,10 +128,10 @@ public class SauceProvider { } } - lastKnownSauce = this.getNewestIndex(); + lastKnownSauce = getNewestIndex(); } - private void initSauceProviding() { + private static void initSauceProviding() { YoshiBot yoshiBot = YoshiBot.getInstance(); try { yoshiBot.jda.awaitReady(); @@ -119,15 +141,15 @@ public class SauceProvider { for (Map.Entry> entry : Resources.getFeedDetails().entrySet()) { List channels = yoshiBot.jda.getTextChannelsByName(entry.getKey(), true); if (channels.size() > 0) { - this.isSauceInit = true; - this.provideSauce(); + isSauceInit = true; + provideSauce(); } else { Logger.logError("Konnte keine Kanaäle finden für die Soße"); } } } - private int getNewestIndex() { + private static int getNewestIndex() { JSONObject result = getParsedSauceData("https://r34-json.herokuapp.com/posts?limit=1&q=index"); int id = result.getJSONArray("posts").getJSONObject(0).getInt("id"); Logger.logDebug("Neuste Soßen-ID: " + id);