| @ -0,0 +1,6 @@ | |||
| # | |||
| # https://help.github.com/articles/dealing-with-line-endings/ | |||
| # | |||
| # These are explicitly windows files and should use crlf | |||
| *.bat text eol=crlf | |||
| @ -0,0 +1,196 @@ | |||
| # ---> Java | |||
| # Compiled class file | |||
| *.class | |||
| # Log file | |||
| *.log | |||
| # BlueJ files | |||
| *.ctxt | |||
| .idea | |||
| # Mobile Tools for Java (J2ME) | |||
| .mtj.tmp/ | |||
| # Package Files # | |||
| *.jar | |||
| *.war | |||
| *.nar | |||
| *.ear | |||
| *.zip | |||
| *.tar.gz | |||
| *.rar | |||
| # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | |||
| hs_err_pid* | |||
| # ---> Eclipse | |||
| .metadata | |||
| bin/ | |||
| tmp/ | |||
| *.tmp | |||
| *.bak | |||
| *.swp | |||
| *~.nib | |||
| local.properties | |||
| .settings/ | |||
| .loadpath | |||
| .recommenders | |||
| # External tool builders | |||
| .externalToolBuilders/ | |||
| # Locally stored "Eclipse launch configurations" | |||
| *.launch | |||
| # PyDev specific (Python IDE for Eclipse) | |||
| *.pydevproject | |||
| # CDT-specific (C/C++ Development Tooling) | |||
| .cproject | |||
| # CDT- autotools | |||
| .autotools | |||
| # Java annotation processor (APT) | |||
| .factorypath | |||
| # PDT-specific (PHP Development Tools) | |||
| .buildpath | |||
| # sbteclipse plugin | |||
| .target | |||
| # Tern plugin | |||
| .tern-project | |||
| # TeXlipse plugin | |||
| .texlipse | |||
| # STS (Spring Tool Suite) | |||
| .springBeans | |||
| # Code Recommenders | |||
| .recommenders/ | |||
| # Annotation Processing | |||
| .apt_generated/ | |||
| .apt_generated_test/ | |||
| # Scala IDE specific (Scala & Java development for Eclipse) | |||
| .cache-main | |||
| .scala_dependencies | |||
| .worksheet | |||
| # Uncomment this line if you wish to ignore the project description file. | |||
| # Typically, this file would be tracked if it contains build/dependency configurations: | |||
| .project | |||
| # ---> Maven | |||
| target/ | |||
| pom.xml.tag | |||
| pom.xml.releaseBackup | |||
| pom.xml.versionsBackup | |||
| pom.xml.next | |||
| release.properties | |||
| dependency-reduced-pom.xml | |||
| buildNumber.properties | |||
| .mvn/timing.properties | |||
| # https://github.com/takari/maven-wrapper#usage-without-binary-jar | |||
| .mvn/wrapper/maven-wrapper.jar | |||
| # ---> JetBrains | |||
| # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider | |||
| # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | |||
| # User-specific stuff | |||
| .idea/**/workspace.xml | |||
| .idea/**/tasks.xml | |||
| .idea/**/usage.statistics.xml | |||
| .idea/**/dictionaries | |||
| .idea/**/shelf | |||
| # Generated files | |||
| .idea/**/contentModel.xml | |||
| # Sensitive or high-churn files | |||
| .idea/**/dataSources/ | |||
| .idea/**/dataSources.ids | |||
| .idea/**/dataSources.local.xml | |||
| .idea/**/sqlDataSources.xml | |||
| .idea/**/dynamic.xml | |||
| .idea/**/uiDesigner.xml | |||
| .idea/**/dbnavigator.xml | |||
| # Gradle | |||
| .idea/**/gradle.xml | |||
| .idea/**/libraries | |||
| # Gradle and Maven with auto-import | |||
| # When using Gradle or Maven with auto-import, you should exclude module files, | |||
| # since they will be recreated, and may cause churn. Uncomment if using | |||
| # auto-import. | |||
| .idea/artifacts | |||
| .idea/compiler.xml | |||
| .idea/jarRepositories.xml | |||
| .idea/modules.xml | |||
| .idea/*.iml | |||
| .idea/modules | |||
| *.iml | |||
| *.ipr | |||
| # CMake | |||
| cmake-build-*/ | |||
| # Mongo Explorer plugin | |||
| .idea/**/mongoSettings.xml | |||
| # File-based project format | |||
| *.iws | |||
| # IntelliJ | |||
| out/ | |||
| # mpeltonen/sbt-idea plugin | |||
| .idea_modules/ | |||
| # JIRA plugin | |||
| atlassian-ide-plugin.xml | |||
| # Cursive Clojure plugin | |||
| .idea/replstate.xml | |||
| # Crashlytics plugin (for Android Studio and IntelliJ) | |||
| com_crashlytics_export_strings.xml | |||
| crashlytics.properties | |||
| crashlytics-build.properties | |||
| fabric.properties | |||
| # Editor-based Rest Client | |||
| .idea/httpRequests | |||
| # Android studio 3.1+ serialized cache file | |||
| .idea/caches/build_file_checksums.ser | |||
| # ---> Gradle | |||
| .gradle | |||
| **/build/ | |||
| !src/**/build/ | |||
| # Ignore Gradle GUI config | |||
| gradle-app.setting | |||
| # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) | |||
| !gradle-wrapper.jar | |||
| # Cache of project | |||
| .gradletasknamecache | |||
| # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 | |||
| # gradle/wrapper/gradle-wrapper.properties | |||
| .classpath | |||
| app/src/main/resources/* | |||
| !app/src/main/resources/.gitkeep | |||
| @ -0,0 +1,11 @@ | |||
| # YoshiBot | |||
| Ein in Java geschriebener Discordbot, der lustige Sachen kann. | |||
| ##Einrichtung | |||
| Ordner app/src/main/resources anlegen und darein die Config.properties anlegen. Diese sollte folgende Werte enthalten: | |||
| - jda_builder_string -> Client Secret | |||
| - audio_source_directory -> Verzeichnis, in dem die Audio-Dateien liegen, auch unter Windows mit / anstatt \ (dieses Verzeichnis sollte natürlich existieren) | |||
| - restrict_commands_to_channel -> Textkanalname, auf dem die Botkommandos empfangen werden | |||
| @ -0,0 +1,38 @@ | |||
| /* | |||
| * This file was generated by the Gradle 'init' task. | |||
| * | |||
| * This generated file contains a sample Java application project to get you started. | |||
| * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle | |||
| * User Manual available at https://docs.gradle.org/6.8.3/userguide/building_java_projects.html | |||
| */ | |||
| plugins { | |||
| // Apply the application plugin to add support for building a CLI application in Java. | |||
| id 'application' | |||
| } | |||
| repositories { | |||
| // Use JCenter for resolving dependencies. | |||
| jcenter() | |||
| } | |||
| dependencies { | |||
| // Use JUnit test framework. | |||
| testImplementation 'junit:junit:4.13' | |||
| // 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.apache.commons', name: 'commons-lang3', version: '3.0' | |||
| } | |||
| application { | |||
| // Define the main class for the application. | |||
| mainClass = 'de.yannicpunktdee.yoshibot.main.Main' | |||
| } | |||
| @ -0,0 +1,30 @@ | |||
| package de.yannicpunktdee.yoshibot.audio; | |||
| import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| import net.dv8tion.jda.api.entities.Guild; | |||
| public class AudioController { | |||
| private Guild guild; | |||
| private AudioPlayer audioPlayer; | |||
| public AudioController(Guild guild) { | |||
| this.guild = guild; | |||
| this.audioPlayer = YoshiBot.audioPlayerManager.createPlayer(); | |||
| audioPlayer.addListener(new AudioPlayerListener(guild.getAudioManager())); | |||
| this.guild.getAudioManager().setSendingHandler(new AudioSendHandlerImpl(audioPlayer)); | |||
| } | |||
| public Guild getGuild() { | |||
| return guild; | |||
| } | |||
| public AudioPlayer getAudioPlayer() { | |||
| return audioPlayer; | |||
| } | |||
| } | |||
| @ -0,0 +1,28 @@ | |||
| package de.yannicpunktdee.yoshibot.audio; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| public class AudioControllerManager { | |||
| public Map<Long, AudioController> audioController; | |||
| public AudioControllerManager() { | |||
| audioController = new ConcurrentHashMap<Long, AudioController>(); | |||
| } | |||
| public AudioController getController(long guildId) { | |||
| AudioController ac = null; | |||
| if(audioController.containsKey(guildId)) | |||
| ac = audioController.get(guildId); | |||
| else { | |||
| ac = new AudioController(YoshiBot.jda.getGuildById(guildId)); | |||
| audioController.put(guildId, ac); | |||
| } | |||
| return ac; | |||
| } | |||
| } | |||
| @ -0,0 +1,39 @@ | |||
| package de.yannicpunktdee.yoshibot.audio; | |||
| import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; | |||
| import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; | |||
| import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; | |||
| import com.sedmelluq.discord.lavaplayer.track.AudioTrack; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| public class AudioLoadResultHandlerImpl implements AudioLoadResultHandler { | |||
| private AudioController audioController; | |||
| public AudioLoadResultHandlerImpl(AudioController audioController) { | |||
| this.audioController = audioController; | |||
| } | |||
| @Override | |||
| public void trackLoaded(AudioTrack track) { | |||
| audioController.getAudioPlayer().playTrack(track); | |||
| } | |||
| @Override | |||
| public void playlistLoaded(AudioPlaylist playlist) { | |||
| System.out.println("Kann aktuell noch keine Playlists abspielen"); | |||
| } | |||
| @Override | |||
| public void noMatches() { | |||
| System.out.println("Nothing found"); | |||
| } | |||
| @Override | |||
| public void loadFailed(FriendlyException exception) { | |||
| System.out.println("Loading failed"); | |||
| } | |||
| } | |||
| @ -0,0 +1,25 @@ | |||
| package de.yannicpunktdee.yoshibot.audio; | |||
| import com.sedmelluq.discord.lavaplayer.player.event.AudioEvent; | |||
| import com.sedmelluq.discord.lavaplayer.player.event.AudioEventListener; | |||
| import net.dv8tion.jda.api.managers.AudioManager; | |||
| public class AudioPlayerListener implements AudioEventListener { | |||
| private AudioManager audioManager; | |||
| public AudioPlayerListener(AudioManager audioManager) { | |||
| this.audioManager = audioManager; | |||
| } | |||
| @Override | |||
| public void onEvent(AudioEvent event) { | |||
| if(event.player.getPlayingTrack() == null) { | |||
| event.player.stopTrack(); | |||
| audioManager.closeAudioConnection(); | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,37 @@ | |||
| package de.yannicpunktdee.yoshibot.audio; | |||
| import java.nio.ByteBuffer; | |||
| import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; | |||
| import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| import net.dv8tion.jda.api.audio.AudioSendHandler; | |||
| public class AudioSendHandlerImpl implements AudioSendHandler { | |||
| private AudioPlayer audioPlayer; | |||
| private AudioFrame lastFrame; | |||
| public AudioSendHandlerImpl(AudioPlayer audioPlayer) { | |||
| this.audioPlayer = audioPlayer; | |||
| } | |||
| @Override | |||
| public boolean canProvide() { | |||
| lastFrame = audioPlayer.provide(); | |||
| return lastFrame != null; | |||
| } | |||
| @Override | |||
| public ByteBuffer provide20MsAudio() { | |||
| return ByteBuffer.wrap(lastFrame.getData()); | |||
| } | |||
| @Override | |||
| public boolean isOpus() { | |||
| return true; | |||
| } | |||
| } | |||
| @ -0,0 +1,43 @@ | |||
| package de.yannicpunktdee.yoshibot.command; | |||
| /** | |||
| * Abstrakte Superklasse für alle Kommandos. | |||
| * @author Yannic Link | |||
| */ | |||
| public abstract class YoshiCommand { | |||
| protected final String[] requiredArguments = {}; | |||
| /** | |||
| * Der Kontext mit dem das Kommando aufgerufen wurde. | |||
| */ | |||
| protected YoshiCommandContext context; | |||
| /** | |||
| * Erzeugt ein neues Kommando, führt es aber noch nicht aus. Es wird ermittelt, ob die Argumentenkombination | |||
| * valide ist und das isOk-Flag gesetzt. Im Fehlerfall wird eine Fehleremeldung spezifiziert. | |||
| * @param context Der Kontext mit dem das Kommando aufgerufen wurde. | |||
| */ | |||
| public YoshiCommand(YoshiCommandContext context) { | |||
| this.context = context; | |||
| } | |||
| /** | |||
| * Führt das Kommando aus. | |||
| * @return True, wenn Ausführung erfolgreich. False, wenn Ausführung fehlgeschlagen. Fehlermeldung wird in | |||
| * errorMessage spezifiziert. | |||
| */ | |||
| public boolean execute() { | |||
| if(!context.containsArguments(requiredArguments)){ | |||
| sendMessage("Fehlende Argumente"); | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| protected void sendMessage(String message) { | |||
| context.getEvent().getTextChannel().sendMessage(message).queue(); | |||
| } | |||
| } | |||
| @ -0,0 +1,288 @@ | |||
| package de.yannicpunktdee.yoshibot.command; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandDistributor.Action; | |||
| 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;; | |||
| /** | |||
| * Parst einen Eingabestring, entscheidet ob er ein Kommando ist und zerlegt ihn in seine Bestandteile. | |||
| * Kommandos besitzen einen Status, der Auskunft gibt, ob Fehler beim Parsen des Eingabestrings aufgetreten | |||
| * sind oder der String gar kein Kommando war. Außerdem wird bei erfolgreich geparsten Kommandos eine Aktion | |||
| * festgelegt, die das Kommando ausführen soll, sowie die Argumente mit welcher das Kommando ausgeführt wird. | |||
| * Außerdem enthalten ist eine Referenz auf Ursprungs-User und -TextChannel. | |||
| * @author Yannic Link | |||
| */ | |||
| public class YoshiCommandContext { | |||
| /** | |||
| * Repräsentiert einen Status, den eine YoshiCommand-Instanz hat, nachdem der Eingabestring eingelesen | |||
| * und geparst wurde. Sofern der Status nicht OK ist, ist diese Instanz entweder kein Kommando oder | |||
| * besitzt eine fehlerhafte Syntax. | |||
| */ | |||
| public static enum State { | |||
| /** | |||
| * Das Kommando wurde erfolgreich geparst und besitzt keine Syntaxfehler. | |||
| */ | |||
| OK, | |||
| /** | |||
| * Der Eingabestring war kein Kommando für den Yoshi-Bot. | |||
| */ | |||
| NO_COMMAND, | |||
| /** | |||
| * Im Kommando wurde keine Aktion spezifiziert. | |||
| */ | |||
| NO_ACTION, | |||
| /** | |||
| * Die angegebene Aktion existiert nicht. | |||
| */ | |||
| UNKNOWN_ACTION, | |||
| /** | |||
| * Das Kommando hatt einen Syntaxfehler. | |||
| */ | |||
| BAD_SYNTAX | |||
| } | |||
| /** | |||
| * Hilfskonstrukt. Beschreibt den Zustand vom Parser. | |||
| */ | |||
| private static enum ReadingState{ | |||
| /** | |||
| * Der Parser ist dabei festzustellen, ob es sich um ein Kommando handelt. | |||
| */ | |||
| VERIFYING, | |||
| /** | |||
| * Zwischenzustand zwischen VERIFYING und READING_ACTION. | |||
| */ | |||
| AFTER_VERIFY, | |||
| /** | |||
| * Der Parser liest die Action ein. | |||
| */ | |||
| READING_ACTION, | |||
| /** | |||
| * Zustand nach READING_ACTION, READING_VALUE oder READING_STRING). | |||
| */ | |||
| INTERMEDIATE, | |||
| /** | |||
| * Der Parser ist dabei einen Argumentenkey einzulesen. | |||
| */ | |||
| READING_KEY, | |||
| /** | |||
| * Der Parser hat gerade einen Argumentenkey eingelesen. | |||
| */ | |||
| AFTER_KEY, | |||
| /** | |||
| * Der Parser liest gerade einen Argumentenwert ein. | |||
| */ | |||
| READING_VALUE, | |||
| /** | |||
| * Der Parser liest gerade einen zusammenhängenden Argumentenwert ein. | |||
| */ | |||
| READING_STRING | |||
| }; | |||
| /** | |||
| * Das Präfix, mit dem Yoshi-Bot-Kommandos beginnen. | |||
| */ | |||
| public static final String PREFIX = "::yoshi"; | |||
| /** | |||
| * Der (Fehler-)Status, den der Parser nach Einlesen des Eingabestrings angenommen hat. | |||
| */ | |||
| private State state; | |||
| /** | |||
| * Die im Eingabesting spezifizierte Aktion. | |||
| */ | |||
| private Action action; | |||
| /** | |||
| * Eine Map, die die Key-Werte der Argumente (ohne Bindestrich) auf dessen Werte abbildet. | |||
| */ | |||
| private Map<String, String> arguments; | |||
| private MessageReceivedEvent event; | |||
| /** | |||
| * Erzeugt aus einem unbearbeiteten Eingabestring ein Kommando. Nach dem parsen enthält die state-Variable | |||
| * den Endzustand des Parsers. | |||
| * @param argumentsString Ein unbearbeiteter Eingabestring | |||
| * @param user Der Benutzer, der das Kommando geschickt hat. | |||
| * @param channel Der Textchannel in den das Kommando geschickt wurde. | |||
| */ | |||
| public YoshiCommandContext(String argumentsString, MessageReceivedEvent event) { | |||
| this.event = event; | |||
| argumentsString = argumentsString.trim(); | |||
| arguments = new HashMap<String, String>(); | |||
| ReadingState readingState = ReadingState.VERIFYING; | |||
| String currentKey = null; | |||
| int startPos = 0; | |||
| int length = argumentsString.length(); | |||
| for(int position = 0; position < length; position++) { | |||
| char currentChar = argumentsString.charAt(position); | |||
| switch(readingState) { | |||
| case VERIFYING: | |||
| if(!Character.isWhitespace(currentChar)) continue; | |||
| if(!argumentsString.substring(0, position).equals(PREFIX)) { | |||
| state = State.NO_COMMAND; | |||
| return; | |||
| } | |||
| readingState = ReadingState.AFTER_VERIFY; | |||
| continue; | |||
| case AFTER_VERIFY: | |||
| if(Character.isWhitespace(currentChar)) continue; | |||
| if(currentChar == '-'){ | |||
| state = State.NO_ACTION; | |||
| return; | |||
| } | |||
| startPos = position; | |||
| readingState = ReadingState.READING_ACTION; | |||
| continue; | |||
| case READING_ACTION: | |||
| if(!Character.isWhitespace(currentChar)) continue; | |||
| try{ | |||
| action = Action.valueOf(argumentsString.substring(startPos, position).toUpperCase()); | |||
| readingState = ReadingState.INTERMEDIATE; | |||
| } catch(IllegalArgumentException e) { | |||
| state = State.UNKNOWN_ACTION; | |||
| return; | |||
| } | |||
| continue; | |||
| case INTERMEDIATE: | |||
| if(Character.isWhitespace(currentChar)) continue; | |||
| if(currentChar != '-' || currentChar == '"') { | |||
| state = State.BAD_SYNTAX; | |||
| return; | |||
| } | |||
| startPos = position + 1; | |||
| readingState = ReadingState.READING_KEY; | |||
| continue; | |||
| case READING_KEY: | |||
| if(!Character.isWhitespace(currentChar)) continue; | |||
| currentKey = argumentsString.substring(startPos, position); | |||
| readingState = ReadingState.AFTER_KEY; | |||
| continue; | |||
| case AFTER_KEY: | |||
| if(Character.isWhitespace(currentChar)) continue; | |||
| if(currentChar == '-') { | |||
| arguments.put(currentKey, null); | |||
| startPos = position + 1; | |||
| readingState = ReadingState.READING_KEY; | |||
| } else if(currentChar == '"'){ | |||
| startPos = position + 1; | |||
| readingState = ReadingState.READING_STRING; | |||
| } else { | |||
| startPos = position; | |||
| readingState = ReadingState.READING_VALUE; | |||
| } | |||
| continue; | |||
| case READING_VALUE: | |||
| if(!Character.isWhitespace(currentChar)) continue; | |||
| arguments.put(currentKey, argumentsString.substring(startPos, position)); | |||
| readingState = ReadingState.INTERMEDIATE; | |||
| continue; | |||
| case READING_STRING: | |||
| if(currentChar != '"') continue; | |||
| if(argumentsString.charAt(position - 1) == '\\') continue; | |||
| arguments.put(currentKey, argumentsString.substring(startPos, position)); | |||
| readingState = ReadingState.INTERMEDIATE; | |||
| continue; | |||
| } | |||
| } | |||
| switch(readingState) { | |||
| case INTERMEDIATE: | |||
| state = State.OK; | |||
| return; | |||
| case VERIFYING: | |||
| if(argumentsString.equals(PREFIX)) { | |||
| action = Action.HELP; | |||
| state = State.OK; | |||
| }else { | |||
| state = State.NO_COMMAND; | |||
| } | |||
| return; | |||
| case READING_ACTION: | |||
| try{ | |||
| action = Action.valueOf(argumentsString.substring(startPos).toUpperCase()); | |||
| readingState = ReadingState.INTERMEDIATE; | |||
| } catch(IllegalArgumentException e) { | |||
| state = State.UNKNOWN_ACTION; | |||
| return; | |||
| } | |||
| state = State.OK; | |||
| return; | |||
| case READING_KEY: | |||
| arguments.put(argumentsString.substring(startPos), null); | |||
| state = State.OK; | |||
| return; | |||
| case READING_VALUE: | |||
| arguments.put(currentKey, argumentsString.substring(startPos)); | |||
| state = State.OK; | |||
| return; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| /** | |||
| * Prüft, ob der Eingabestring ein valides Kommando war. | |||
| */ | |||
| public boolean isValid() { | |||
| return state.equals(State.OK); | |||
| } | |||
| /** | |||
| * Gibt den (Fehler-)Status des Parsers zurück. | |||
| */ | |||
| public State getState() { | |||
| return state; | |||
| } | |||
| /** | |||
| * Gibt die im Kommando spezifizierte Aktion zurück. null, wenn status fehlerhaft oder kein Kommando. | |||
| */ | |||
| public Action getAction() { | |||
| return action; | |||
| } | |||
| /** | |||
| * Prüft, ob das Kommando mit Argumenten aufgerufen wurde. | |||
| */ | |||
| public boolean hasArguments() { | |||
| return !arguments.isEmpty(); | |||
| } | |||
| /** | |||
| * Prüft, ob alle Key-Werte in der Argumentenliste vorhanden sind. | |||
| * @param args Liste von den auf Existenz zu überprüfenden Argumenten. | |||
| */ | |||
| public boolean containsArguments(String[] args) { | |||
| for(String arg : args) { | |||
| if(!arguments.containsKey(arg)) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| /** | |||
| * Gibt den Wert eines Arguments zurück. | |||
| * @param arg Name des Arguments. | |||
| */ | |||
| public String getArgument(String arg) { | |||
| if(!arguments.containsKey(arg)) return null; | |||
| return arguments.get(arg); | |||
| } | |||
| public MessageReceivedEvent getEvent() { | |||
| return event; | |||
| } | |||
| } | |||
| @ -0,0 +1,106 @@ | |||
| package de.yannicpunktdee.yoshibot.command; | |||
| import de.yannicpunktdee.yoshibot.command.commands.HelpCommand; | |||
| import de.yannicpunktdee.yoshibot.command.commands.JokeCommand; | |||
| import de.yannicpunktdee.yoshibot.command.commands.PlayCommand; | |||
| import de.yannicpunktdee.yoshibot.command.commands.SayCommand; | |||
| import de.yannicpunktdee.yoshibot.command.commands.StopCommand; | |||
| /** | |||
| * Unterscheidet nach der spezifizierten Action welche YoshiCommand-Kindklasse zum Ausführen des Kommandos | |||
| * verwendet wird. | |||
| * @author Yannic Link | |||
| */ | |||
| public class YoshiCommandDistributor { | |||
| /** | |||
| * Führt das jeweils zuständige Kommando aus. | |||
| * @param context | |||
| */ | |||
| public static void distribute(YoshiCommandContext context) { | |||
| switch(context.getState()) { | |||
| case NO_ACTION: | |||
| context.getEvent().getTextChannel().sendMessage("Im letzten Befehl wurde keine Aktion spezifiziert. Führe \"" | |||
| + YoshiCommandContext.PREFIX + " help\" für Hilfe aus.").queue(); | |||
| return; | |||
| case UNKNOWN_ACTION: | |||
| context.getEvent().getTextChannel().sendMessage("Im letzten Befehl wurde eine unbekannte Aktion angegeben. Führe \"" | |||
| + YoshiCommandContext.PREFIX + " help\" für Hilfe aus.").queue(); | |||
| return; | |||
| case BAD_SYNTAX: | |||
| context.getEvent().getTextChannel().sendMessage("Der letzte Befehl hatte ein falsches Format. Führe \"" | |||
| + YoshiCommandContext.PREFIX + " help\" für Hilfe aus.").queue(); | |||
| return; | |||
| default: | |||
| break; | |||
| } | |||
| YoshiCommand command = null; | |||
| switch(context.getAction()) { | |||
| case STOP: | |||
| command = new StopCommand(context); | |||
| break; | |||
| case HELP: | |||
| command = new HelpCommand(context); | |||
| break; | |||
| case JOKE: | |||
| command = new JokeCommand(context); | |||
| break; | |||
| case SAY: | |||
| command = new SayCommand(context); | |||
| break; | |||
| case PLAY: | |||
| command = new PlayCommand(context); | |||
| break; | |||
| default: | |||
| context.getEvent().getTextChannel().sendMessage("Dieses Kommando existiert noch nicht.").queue(); | |||
| break; | |||
| } | |||
| if(command != null) command.execute(); | |||
| } | |||
| /** | |||
| * Enth�lt alle m�glichen Aktionen, die der Yoshi-Bot ausf�hren kann. | |||
| * @author Yannic Link | |||
| */ | |||
| public enum Action { | |||
| /** | |||
| * Sende eine Hilfe-Nachricht, in der die Benutzung des Yoshi-Bots dokumentiert ist. | |||
| */ | |||
| HELP, | |||
| /** | |||
| * Fahre den Yoshi-Bot herunter (nur mit speziellen Berechtigungen m�glich). | |||
| */ | |||
| STOP, | |||
| /** | |||
| * Erzählt einen Jokus. | |||
| */ | |||
| JOKE, | |||
| /** | |||
| * Gib die Nachricht -message aus. �ber die Option -out [text|voice] wird angegeben, ob die Nachricht | |||
| * per Textnachricht oder als Text-To-Speech ausgegeben wird. Mit -channel l�sst sich der Ausgabechannel | |||
| * bestimmen. Standardm��ig wird die Ausgabe in den Textchannel zur�ckgesendet, aus dem das Kommando kam. | |||
| */ | |||
| SAY, | |||
| /** | |||
| * Listet alle zugewiesenen Ressourcen auf. Mit der Option -type [all|link|audio|video] l�sst sich das Format | |||
| * der Ressource spezifizieren. | |||
| */ | |||
| LIST, | |||
| /** | |||
| * Gibt eine vorhandene Ressource -name aus. (Vorhandene Ressourcen lassen sich mit der Aktion LIST anzeigen). | |||
| * �ber den Parameter -type [link|audio|video] l�sst sich der Typ der Ressource spezifizieren. Ein Link wird | |||
| * �ber in den per -channel spezifizierten (default=Ursprungskanal) Textkanal geschickt. Eine Audiodatei | |||
| * wird �ber den per -channel spezifizierten (default=Aktueller Kanal) Voice-Channel ausgegeben. Ein Video | |||
| * wird �ber den per -channel spezifizierten (default=Aktueller Kanal) Voice-Channel abgespielt. | |||
| */ | |||
| PLAY, | |||
| /** | |||
| * L�scht die Ressource, die �ber -name spezifiziert wurde. Mit -type wird der Ressourcentyp festgelegt. | |||
| */ | |||
| DELETE | |||
| } | |||
| } | |||
| @ -0,0 +1,15 @@ | |||
| package de.yannicpunktdee.yoshibot.command.commands; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommand; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; | |||
| public class HelpCommand extends YoshiCommand { | |||
| public HelpCommand(YoshiCommandContext context) { | |||
| super(context); | |||
| } | |||
| @Override | |||
| public boolean execute() {return true;} | |||
| } | |||
| @ -0,0 +1,140 @@ | |||
| package de.yannicpunktdee.yoshibot.command.commands; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.net.HttpURLConnection; | |||
| import java.net.URL; | |||
| import java.util.List; | |||
| import java.util.Random; | |||
| import org.apache.commons.lang3.StringEscapeUtils; | |||
| import org.json.JSONException; | |||
| import org.json.JSONObject; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommand; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| import net.dv8tion.jda.api.entities.TextChannel; | |||
| /** | |||
| * Schickt einen zufälligen Jokus aus einer zufällig ausgewählten Quelle in den Textchannel. | |||
| * @author Yannic Link | |||
| */ | |||
| @SuppressWarnings("deprecation") | |||
| public class JokeCommand extends YoshiCommand { | |||
| /** | |||
| * Erstellt einen neuen JokeCommand. | |||
| */ | |||
| public JokeCommand(YoshiCommandContext context) { | |||
| super(context); | |||
| } | |||
| /** | |||
| * {@inheritDoc} | |||
| */ | |||
| @Override public synchronized boolean execute() { | |||
| String message = "Jokus"; | |||
| Random random = new Random(); | |||
| int number = random.nextInt(3); | |||
| switch(number) { | |||
| case 0: message = jokeApi(); break; | |||
| case 1: message = officialJokeApi(); break; | |||
| case 2: message = chuckNorris(); break; | |||
| default: message = "Jokus"; break; | |||
| } | |||
| if(context.containsArguments(new String[] {"channel"})) { | |||
| String arg = context.getArgument("channel"); | |||
| if(arg == null) { | |||
| sendMessage("Es wurde kein channel angegeben."); | |||
| return false; | |||
| } | |||
| List<TextChannel> channels = YoshiBot.jda.getTextChannelsByName(context.getArgument("channel"), true); | |||
| if(channels.isEmpty()) { | |||
| sendMessage("Der Kanalname konnte nicht gefunden werden."); | |||
| return false; | |||
| } | |||
| channels.get(0).sendMessage(message).queue(); | |||
| }else { | |||
| sendMessage(message); | |||
| } | |||
| return true; | |||
| } | |||
| private String getFromURL(String url) throws IOException { | |||
| StringBuilder response = new StringBuilder(""); | |||
| HttpURLConnection con = null; | |||
| try{ | |||
| con = (HttpURLConnection)(new URL(url)).openConnection(); | |||
| con.setRequestMethod("GET"); | |||
| BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream())); | |||
| String line; | |||
| while((line = br.readLine()) != null) { | |||
| response.append(StringEscapeUtils.unescapeHtml4(line)); | |||
| } | |||
| br.close(); | |||
| }catch(IOException e) { | |||
| return null; | |||
| }finally { | |||
| if(con != null) con.disconnect(); | |||
| } | |||
| return response.toString(); | |||
| } | |||
| private String chuckNorris() { | |||
| String url = "http://api.icndb.com/jokes/random"; | |||
| JSONObject json = null; | |||
| try { | |||
| String raw = getFromURL(url); | |||
| json = new JSONObject(raw); | |||
| return json.getJSONObject("value").getString("joke"); | |||
| }catch(JSONException | IOException e) { | |||
| return "Konnte keinen Jokus von \"" + url + "\" laden."; | |||
| } | |||
| } | |||
| private String officialJokeApi() { | |||
| String url = "https://official-joke-api.appspot.com/jokes/random"; | |||
| JSONObject json = null; | |||
| try { | |||
| String raw = getFromURL(url); | |||
| json = new JSONObject(raw); | |||
| String result = json.getString("setup"); | |||
| result += " - "; | |||
| result += json.getString("punchline"); | |||
| return result; | |||
| }catch(JSONException | IOException e) { | |||
| return "Konnte keinen Jokus von \"" + url + "\" laden."; | |||
| } | |||
| } | |||
| private String jokeApi() { | |||
| String url = "https://v2.jokeapi.dev/joke/any"; | |||
| JSONObject json = null; | |||
| try { | |||
| String raw = getFromURL(url); | |||
| json = new JSONObject(raw); | |||
| String result = json.getString("setup"); | |||
| result += " - "; | |||
| result += json.getString("delivery"); | |||
| return result; | |||
| }catch(JSONException | IOException e) { | |||
| return "Konnte keinen Jokus von \"" + url + "\" laden."; | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,46 @@ | |||
| package de.yannicpunktdee.yoshibot.command.commands; | |||
| import java.util.List; | |||
| 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.main.YoshiBot; | |||
| import net.dv8tion.jda.api.entities.VoiceChannel; | |||
| public class PlayCommand extends YoshiCommand { | |||
| protected final String[] requiredArguments = new String[] {"channel", "name"}; | |||
| public PlayCommand(YoshiCommandContext context) { | |||
| super(context); | |||
| } | |||
| @Override | |||
| public boolean execute() { | |||
| if(!super.execute()) return false; | |||
| List<VoiceChannel> channels = YoshiBot.jda.getVoiceChannelsByName(context.getArgument("channel"), true); | |||
| if(!(channels.size() > 0)) { | |||
| context.getEvent().getTextChannel().sendMessage("Der Kanalname konnte nicht gefunden werden.").queue(); | |||
| return false; | |||
| } | |||
| VoiceChannel vc = channels.get(0); | |||
| String fileName = Resources.getAudioFilePath(context.getArgument("name")); | |||
| if(fileName == null) { | |||
| context.getEvent().getTextChannel().sendMessage("Audio konnte nicht gefunden werden.").queue(); | |||
| return false; | |||
| } | |||
| AudioController ac = YoshiBot.audioControllerManager.getController(vc.getGuild().getIdLong()); | |||
| vc.getGuild().getAudioManager().openAudioConnection(vc); | |||
| YoshiBot.audioPlayerManager.loadItem(fileName, new AudioLoadResultHandlerImpl(ac)); | |||
| return true; | |||
| } | |||
| } | |||
| @ -0,0 +1,15 @@ | |||
| package de.yannicpunktdee.yoshibot.command.commands; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommand; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; | |||
| public class SayCommand extends YoshiCommand { | |||
| public SayCommand(YoshiCommandContext context) { | |||
| super(context); | |||
| } | |||
| @Override | |||
| public boolean execute() {return true;} | |||
| } | |||
| @ -0,0 +1,23 @@ | |||
| package de.yannicpunktdee.yoshibot.command.commands; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommand; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| public class StopCommand extends YoshiCommand { | |||
| protected final String[] requiredArguments = {"please", "uwu"}; | |||
| public StopCommand(YoshiCommandContext context) { | |||
| super(context); | |||
| } | |||
| @Override | |||
| public boolean execute() { | |||
| if(!super.execute()) return false; | |||
| YoshiBot.stop(); | |||
| return true; | |||
| } | |||
| } | |||
| @ -0,0 +1,44 @@ | |||
| package de.yannicpunktdee.yoshibot.listeners; | |||
| import java.io.BufferedReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| public class CommandLine extends Thread implements Runnable { | |||
| private BufferedReader reader; | |||
| /** | |||
| * Nicht manuell aufrufen. Wird einmalig in startYoshiBot in einem neuen Thread aufgerufen und reagiert | |||
| * auf administrative Konsoleneingaben außerhalb von Discord. | |||
| */ | |||
| @Override public void run() { | |||
| String line = ""; | |||
| reader = new BufferedReader(new InputStreamReader(System.in)); | |||
| try { | |||
| System.out.print("> "); | |||
| while((line = reader.readLine()) != null) { | |||
| line = line.trim(); | |||
| if(line.equalsIgnoreCase("exit")) { | |||
| YoshiBot.stop(); | |||
| return; | |||
| } | |||
| System.out.print("> "); | |||
| } | |||
| } catch(IOException e) { | |||
| System.err.println("Es ist eine IOException aufgetreten."); | |||
| } | |||
| } | |||
| public void stopCommandLine() { | |||
| try { | |||
| reader.close(); | |||
| interrupt(); | |||
| } catch (IOException e) { | |||
| System.err.println("Fehler beim Schließen des Readers."); | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,39 @@ | |||
| package de.yannicpunktdee.yoshibot.listeners; | |||
| import de.yannicpunktdee.yoshibot.command.YoshiCommandContext; | |||
| import de.yannicpunktdee.yoshibot.main.Resources; | |||
| import de.yannicpunktdee.yoshibot.main.YoshiBot; | |||
| import net.dv8tion.jda.api.entities.ChannelType; | |||
| import net.dv8tion.jda.api.events.message.MessageReceivedEvent; | |||
| import net.dv8tion.jda.api.hooks.ListenerAdapter; | |||
| /** | |||
| * Lauscht auf eingehende Nachrichten und leitet diese an die YoshiBot.executeCommand-Methode weiter, | |||
| * falls es sich um ein Kommando handelt. | |||
| * @author Yannic Link | |||
| */ | |||
| public class CommandListener extends ListenerAdapter { | |||
| /** | |||
| * {@inheritDoc} | |||
| */ | |||
| @Override public void onMessageReceived(MessageReceivedEvent event) { | |||
| if(!event.isFromType(ChannelType.TEXT)) return; | |||
| if(event.getAuthor().isBot()) return; | |||
| if(Resources.getRestrictCommandsToChannel() != null | |||
| && !Resources.getRestrictCommandsToChannel().equalsIgnoreCase(event.getTextChannel().getName())) | |||
| return; | |||
| String raw = event.getMessage().getContentRaw().trim(); | |||
| if(!raw.startsWith(YoshiCommandContext.PREFIX)) return; | |||
| YoshiCommandContext context = new YoshiCommandContext(raw, event); | |||
| if(!context.getState().equals(YoshiCommandContext.State.NO_COMMAND)) YoshiBot.executeCommand(context); | |||
| return; | |||
| } | |||
| } | |||
| @ -0,0 +1,29 @@ | |||
| package de.yannicpunktdee.yoshibot.main; | |||
| import java.net.URISyntaxException; | |||
| import javax.security.auth.login.LoginException; | |||
| /** | |||
| * 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 | |||
| */ | |||
| public static void main(String[] args) throws URISyntaxException { | |||
| System.out.println("Starte Applikation.\n"); | |||
| YoshiBot.init((args.length > 0)? args[0] : null); | |||
| try { | |||
| YoshiBot.start(); | |||
| }catch(LoginException e) { | |||
| System.err.println("Es ist ein Fehler beim Login aufgetreten."); | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,77 @@ | |||
| package de.yannicpunktdee.yoshibot.main; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.util.Properties; | |||
| public class Resources { | |||
| private static final String default_propertiesFilePath = "Config.properties"; | |||
| private static String propertiesFilePath = default_propertiesFilePath; | |||
| private static Properties propertiesFile; | |||
| private static String jda_builder_string; | |||
| private static final String default_audio_source_directory = "rsc/audio/"; | |||
| private static String audio_source_directory = default_audio_source_directory; | |||
| private static final String default_restrict_commands_to_channel = null; | |||
| private static String restrict_commands_to_channel = default_restrict_commands_to_channel; | |||
| public synchronized static void init(String pathToConfig) { | |||
| if(pathToConfig != null) propertiesFilePath = pathToConfig; | |||
| if(!(new File(propertiesFilePath)).exists()) propertiesFilePath = default_propertiesFilePath; | |||
| propertiesFile = new Properties(); | |||
| try { | |||
| propertiesFile.load(Resources.class.getClassLoader().getResourceAsStream(propertiesFilePath)); | |||
| System.out.println("Properties-Datei erfolgreich geladen."); | |||
| } catch (IOException e) { | |||
| System.err.println("Es wurde keine Config-Datei gefunden. Benutze Standards."); | |||
| return; | |||
| } | |||
| initJdaBuilderString(); | |||
| initAudio(); | |||
| initChannelRestrict(); | |||
| } | |||
| private static void initJdaBuilderString() { | |||
| if(!propertiesFile.containsKey("jda_builder_string")) { | |||
| System.err.println("Es wurde kein jda_builder_string gefunden."); | |||
| YoshiBot.stop(); | |||
| } else jda_builder_string = propertiesFile.getProperty("jda_builder_string"); | |||
| } | |||
| public static String getJdaBuilderString() { | |||
| return jda_builder_string; | |||
| } | |||
| private static void initAudio() { | |||
| if(!propertiesFile.containsKey("audio_source_directory")) return; | |||
| String dir = propertiesFile.getProperty("audio_source_directory"); | |||
| File file = new File(dir); | |||
| if(!file.exists() || !file.isDirectory()){ | |||
| System.err.println("Das Audio-Verzeichnis wurde nicht gefunden"); | |||
| return; | |||
| } | |||
| audio_source_directory = dir; | |||
| } | |||
| public static String getAudioFilePath(String name) { | |||
| name = audio_source_directory + (audio_source_directory.endsWith("/")? "" : "/") + name + ".opus"; | |||
| System.out.println("Dateiname: " + name); | |||
| if((new File(name)).exists()) return name; | |||
| else return null; | |||
| } | |||
| private static void initChannelRestrict() { | |||
| if(propertiesFile.containsKey("restrict_commands_to_channel")) | |||
| restrict_commands_to_channel = propertiesFile.getProperty("restrict_commands_to_channel"); | |||
| } | |||
| public static String getRestrictCommandsToChannel() { | |||
| return restrict_commands_to_channel; | |||
| } | |||
| } | |||
| @ -0,0 +1,99 @@ | |||
| package de.yannicpunktdee.yoshibot.main; | |||
| import javax.security.auth.login.LoginException; | |||
| import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; | |||
| import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; | |||
| import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; | |||
| import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager; | |||
| import de.yannicpunktdee.yoshibot.audio.AudioControllerManager; | |||
| 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 net.dv8tion.jda.api.JDA; | |||
| import net.dv8tion.jda.api.JDABuilder; | |||
| import net.dv8tion.jda.api.OnlineStatus; | |||
| import net.dv8tion.jda.api.entities.Activity; | |||
| /** | |||
| * Repräsentiert einen Yoshi-Bot. Der Bot initialisiert alle Ressourcen und schaltet sich in der | |||
| * startYoshiBot-Methode online und beginnt dann zu lauschen. Parallel lauscht ein Thread auf | |||
| * Konsoleneingaben für administrative Zwecke, die nicht über den Chat erledigt werden sollten. | |||
| * @author Yannic Link | |||
| */ | |||
| public class YoshiBot { | |||
| private static CommandLine commandLineThread; | |||
| /** | |||
| * Erlaubt es einige Einstellungen vor und nach der Erzeugung eines Bots vorzunehmen. | |||
| */ | |||
| public static JDABuilder jdaBuilder; | |||
| /** | |||
| * Instanz vom aktuell laufenden Bot. | |||
| */ | |||
| public static JDA jda; | |||
| /** | |||
| * LavaPlayer AudioPlayerManager. | |||
| */ | |||
| public static AudioPlayerManager audioPlayerManager; | |||
| public static AudioControllerManager audioControllerManager; | |||
| /** | |||
| * Initialisiert alle dynamisch hinzugefügten und statischen Ressourcen. Startet aber nicht | |||
| * den Bot selbst. | |||
| */ | |||
| public static void init(String configPath) { | |||
| Resources.init(configPath); | |||
| } | |||
| /** | |||
| * Startet den Bot und schaltet ihn online. Beginnt auf Konsoleneingaben für administrative | |||
| * Zwecke zu lauschen. | |||
| * @throws LoginException Falls das Token ungültig ist. | |||
| */ | |||
| public static void start() throws LoginException { | |||
| System.out.println("Starte YoshiBot."); | |||
| jdaBuilder = JDABuilder.createDefault(Resources.getJdaBuilderString()); | |||
| jdaBuilder.addEventListeners(new CommandListener()); | |||
| audioPlayerManager = new DefaultAudioPlayerManager(); | |||
| audioPlayerManager.registerSourceManager(new LocalAudioSourceManager()); | |||
| AudioSourceManagers.registerRemoteSources(audioPlayerManager); | |||
| audioControllerManager = new AudioControllerManager(); | |||
| jda = jdaBuilder.build(); | |||
| jdaBuilder.setActivity(Activity.playing("Haare waschen.")); | |||
| jdaBuilder.setStatus(OnlineStatus.ONLINE); | |||
| System.out.println("YoshiBot online."); | |||
| commandLineThread = new CommandLine(); | |||
| commandLineThread.start(); | |||
| } | |||
| public static synchronized void stop() { | |||
| commandLineThread.stopCommandLine(); | |||
| System.out.println("Beende YoshiBot ..."); | |||
| jdaBuilder.setStatus(OnlineStatus.OFFLINE); | |||
| jda.shutdown(); | |||
| System.out.println("YoshiBot offline."); | |||
| } | |||
| /** | |||
| * Leitet den Context an den CommandDistributor weiter. | |||
| * @param command Der Kontext für das Kommando. | |||
| */ | |||
| public static void executeCommand(YoshiCommandContext command) { | |||
| YoshiCommandDistributor.distribute(command); | |||
| } | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| distributionBase=GRADLE_USER_HOME | |||
| distributionPath=wrapper/dists | |||
| distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip | |||
| zipStoreBase=GRADLE_USER_HOME | |||
| zipStorePath=wrapper/dists | |||
| @ -0,0 +1,185 @@ | |||
| #!/usr/bin/env sh | |||
| # | |||
| # Copyright 2015 the original author or authors. | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # https://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| # | |||
| ############################################################################## | |||
| ## | |||
| ## Gradle start up script for UN*X | |||
| ## | |||
| ############################################################################## | |||
| # Attempt to set APP_HOME | |||
| # Resolve links: $0 may be a link | |||
| PRG="$0" | |||
| # Need this for relative symlinks. | |||
| while [ -h "$PRG" ] ; do | |||
| ls=`ls -ld "$PRG"` | |||
| link=`expr "$ls" : '.*-> \(.*\)$'` | |||
| if expr "$link" : '/.*' > /dev/null; then | |||
| PRG="$link" | |||
| else | |||
| PRG=`dirname "$PRG"`"/$link" | |||
| fi | |||
| done | |||
| SAVED="`pwd`" | |||
| cd "`dirname \"$PRG\"`/" >/dev/null | |||
| APP_HOME="`pwd -P`" | |||
| cd "$SAVED" >/dev/null | |||
| APP_NAME="Gradle" | |||
| APP_BASE_NAME=`basename "$0"` | |||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
| DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | |||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | |||
| MAX_FD="maximum" | |||
| warn () { | |||
| echo "$*" | |||
| } | |||
| die () { | |||
| echo | |||
| echo "$*" | |||
| echo | |||
| exit 1 | |||
| } | |||
| # OS specific support (must be 'true' or 'false'). | |||
| cygwin=false | |||
| msys=false | |||
| darwin=false | |||
| nonstop=false | |||
| case "`uname`" in | |||
| CYGWIN* ) | |||
| cygwin=true | |||
| ;; | |||
| Darwin* ) | |||
| darwin=true | |||
| ;; | |||
| MINGW* ) | |||
| msys=true | |||
| ;; | |||
| NONSTOP* ) | |||
| nonstop=true | |||
| ;; | |||
| esac | |||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |||
| # Determine the Java command to use to start the JVM. | |||
| if [ -n "$JAVA_HOME" ] ; then | |||
| if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||
| # IBM's JDK on AIX uses strange locations for the executables | |||
| JAVACMD="$JAVA_HOME/jre/sh/java" | |||
| else | |||
| JAVACMD="$JAVA_HOME/bin/java" | |||
| fi | |||
| if [ ! -x "$JAVACMD" ] ; then | |||
| die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |||
| Please set the JAVA_HOME variable in your environment to match the | |||
| location of your Java installation." | |||
| fi | |||
| else | |||
| JAVACMD="java" | |||
| which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
| Please set the JAVA_HOME variable in your environment to match the | |||
| location of your Java installation." | |||
| fi | |||
| # Increase the maximum file descriptors if we can. | |||
| if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | |||
| MAX_FD_LIMIT=`ulimit -H -n` | |||
| if [ $? -eq 0 ] ; then | |||
| if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |||
| MAX_FD="$MAX_FD_LIMIT" | |||
| fi | |||
| ulimit -n $MAX_FD | |||
| if [ $? -ne 0 ] ; then | |||
| warn "Could not set maximum file descriptor limit: $MAX_FD" | |||
| fi | |||
| else | |||
| warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |||
| fi | |||
| fi | |||
| # For Darwin, add options to specify how the application appears in the dock | |||
| if $darwin; then | |||
| GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||
| fi | |||
| # For Cygwin or MSYS, switch paths to Windows format before running java | |||
| if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then | |||
| APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |||
| CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |||
| JAVACMD=`cygpath --unix "$JAVACMD"` | |||
| # We build the pattern for arguments to be converted via cygpath | |||
| ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |||
| SEP="" | |||
| for dir in $ROOTDIRSRAW ; do | |||
| ROOTDIRS="$ROOTDIRS$SEP$dir" | |||
| SEP="|" | |||
| done | |||
| OURCYGPATTERN="(^($ROOTDIRS))" | |||
| # Add a user-defined pattern to the cygpath arguments | |||
| if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |||
| OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |||
| fi | |||
| # Now convert the arguments - kludge to limit ourselves to /bin/sh | |||
| i=0 | |||
| for arg in "$@" ; do | |||
| CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |||
| CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |||
| if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |||
| eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |||
| else | |||
| eval `echo args$i`="\"$arg\"" | |||
| fi | |||
| i=`expr $i + 1` | |||
| done | |||
| case $i in | |||
| 0) set -- ;; | |||
| 1) set -- "$args0" ;; | |||
| 2) set -- "$args0" "$args1" ;; | |||
| 3) set -- "$args0" "$args1" "$args2" ;; | |||
| 4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |||
| 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |||
| 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |||
| 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |||
| 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |||
| 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |||
| esac | |||
| fi | |||
| # Escape application args | |||
| save () { | |||
| for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | |||
| echo " " | |||
| } | |||
| APP_ARGS=`save "$@"` | |||
| # Collect all arguments for the java command, following the shell quoting and substitution rules | |||
| eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | |||
| exec "$JAVACMD" "$@" | |||
| @ -0,0 +1,89 @@ | |||
| @rem | |||
| @rem Copyright 2015 the original author or authors. | |||
| @rem | |||
| @rem Licensed under the Apache License, Version 2.0 (the "License"); | |||
| @rem you may not use this file except in compliance with the License. | |||
| @rem You may obtain a copy of the License at | |||
| @rem | |||
| @rem https://www.apache.org/licenses/LICENSE-2.0 | |||
| @rem | |||
| @rem Unless required by applicable law or agreed to in writing, software | |||
| @rem distributed under the License is distributed on an "AS IS" BASIS, | |||
| @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| @rem See the License for the specific language governing permissions and | |||
| @rem limitations under the License. | |||
| @rem | |||
| @if "%DEBUG%" == "" @echo off | |||
| @rem ########################################################################## | |||
| @rem | |||
| @rem Gradle startup script for Windows | |||
| @rem | |||
| @rem ########################################################################## | |||
| @rem Set local scope for the variables with windows NT shell | |||
| if "%OS%"=="Windows_NT" setlocal | |||
| set DIRNAME=%~dp0 | |||
| if "%DIRNAME%" == "" set DIRNAME=. | |||
| set APP_BASE_NAME=%~n0 | |||
| set APP_HOME=%DIRNAME% | |||
| @rem Resolve any "." and ".." in APP_HOME to make it shorter. | |||
| for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi | |||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
| set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | |||
| @rem Find java.exe | |||
| if defined JAVA_HOME goto findJavaFromJavaHome | |||
| set JAVA_EXE=java.exe | |||
| %JAVA_EXE% -version >NUL 2>&1 | |||
| if "%ERRORLEVEL%" == "0" goto execute | |||
| echo. | |||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
| echo. | |||
| echo Please set the JAVA_HOME variable in your environment to match the | |||
| echo location of your Java installation. | |||
| goto fail | |||
| :findJavaFromJavaHome | |||
| set JAVA_HOME=%JAVA_HOME:"=% | |||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||
| if exist "%JAVA_EXE%" goto execute | |||
| echo. | |||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |||
| echo. | |||
| echo Please set the JAVA_HOME variable in your environment to match the | |||
| echo location of your Java installation. | |||
| goto fail | |||
| :execute | |||
| @rem Setup the command line | |||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |||
| @rem Execute Gradle | |||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* | |||
| :end | |||
| @rem End local scope for the variables with windows NT shell | |||
| if "%ERRORLEVEL%"=="0" goto mainEnd | |||
| :fail | |||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |||
| rem the _cmd.exe /c_ return code! | |||
| if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |||
| exit /b 1 | |||
| :mainEnd | |||
| if "%OS%"=="Windows_NT" endlocal | |||
| :omega | |||
| @ -0,0 +1,11 @@ | |||
| /* | |||
| * This file was generated by the Gradle 'init' task. | |||
| * | |||
| * The settings file is used to specify which projects to include in your build. | |||
| * | |||
| * Detailed information about configuring a multi-project build in Gradle can be found | |||
| * in the user manual at https://docs.gradle.org/6.8.3/userguide/multi_project_builds.html | |||
| */ | |||
| rootProject.name = 'YoshiBot' | |||
| include('app') | |||