diff --git a/README.md b/README.md
index 452ef87..ea45eae 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ Made this simple multi chat-client bot to access radarr, sonarr, and lidarr with
- [x] User requests audited to local database\
- [x] Blacklist content by paths from showing up in searches
- [x] Get status of radarr, lidarr, sonarr, and any additional configured endpoints
+- [x] Discord slash commands
- [ ] Lookup torrents for movies and force download
- [ ] Cancel/blacklist existing downloads
- [ ] Episode/season search
@@ -51,6 +52,17 @@ Made this simple multi chat-client bot to access radarr, sonarr, and lidarr with
See https://github.com/shayaantx/botdarr/wiki/Install-Discord-Bot
+Slash commands installation/updates:
+- By default, slash commands are automatically available now
+- You can no longer use / with discord as that is reserved for slash commands
+- If you are trying to use slash commands, you will need to update your bots permission to include slash commands, then re-invite your bot your discord server
+- It can take up to 1 hour for discord slash commands to appear
+- If you don't see them after an hour, try disabling one of the commands, and re-enabling it. This workarounds the following bug I've noticed in desktop discord client
+ https://stackoverflow.com/questions/72111433/discord-bot-slash-command-not-appear-on-win10
+ https://github.com/discord/discord-api-docs/issues/4859
+ https://github.com/discord/discord-api-docs/issues/4856
+- Slash commands from botdarr operate the same except they are not the same case (i.e., all the commands have dashes in them)
+
## Slack Bot Installation
See https://github.com/shayaantx/botdarr/wiki/Install-Slack-Bot
diff --git a/images/oauth2-permissions.png b/images/oauth2-permissions.png
index 334722c..f934be5 100644
Binary files a/images/oauth2-permissions.png and b/images/oauth2-permissions.png differ
diff --git a/pom.xml b/pom.xml
index e82ae19..2656dde 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,11 @@
jcenter-bintray
https://jcenter.bintray.com
+
+ dv8tion
+ m2-dv8tion
+ https://m2.dv8tion.net/releases
+
@@ -29,7 +34,7 @@
net.dv8tion
JDA
- 4.2.0_168
+ 4.4.0_350
jar
compile
diff --git a/src/main/java/com/botdarr/Config.java b/src/main/java/com/botdarr/Config.java
index 3f900e7..a62e778 100644
--- a/src/main/java/com/botdarr/Config.java
+++ b/src/main/java/com/botdarr/Config.java
@@ -178,6 +178,17 @@ public static int getTimeout() {
return 5000;
}
+ /**
+ * @return The command prefix
+ */
+ public static String getPrefix() {
+ String configuredPrefix = Config.getProperty(Config.Constants.COMMAND_PREFIX);
+ if (!Strings.isEmpty(configuredPrefix)) {
+ return configuredPrefix;
+ }
+ return "!";
+ }
+
private static StatusEndPoint getDomain(String constant, String name) {
try {
URI uri = new URI(getProperty(constant));
diff --git a/src/main/java/com/botdarr/api/lidarr/LidarrAlbum.java b/src/main/java/com/botdarr/api/lidarr/LidarrAlbum.java
new file mode 100644
index 0000000..4d7aabc
--- /dev/null
+++ b/src/main/java/com/botdarr/api/lidarr/LidarrAlbum.java
@@ -0,0 +1,16 @@
+package com.botdarr.api.lidarr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LidarrAlbum {
+ public List getImages() {
+ return images;
+ }
+
+ public void setImages(List images) {
+ this.images = images;
+ }
+
+ private List images = new ArrayList<>();
+}
diff --git a/src/main/java/com/botdarr/api/lidarr/LidarrApi.java b/src/main/java/com/botdarr/api/lidarr/LidarrApi.java
index 6ac2008..3dcb4ba 100644
--- a/src/main/java/com/botdarr/api/lidarr/LidarrApi.java
+++ b/src/main/java/com/botdarr/api/lidarr/LidarrApi.java
@@ -305,4 +305,5 @@ private CommandResponse addArtist(LidarrArtist lidarrArtist) {
private static final LidarrCache LIDARR_CACHE = new LidarrCache();
public static final String ADD_ARTIST_COMMAND_FIELD_PREFIX = "Add artist command";
+ public static final String ARTIST_LOOKUP_KEY_FIELD = "ForeignArtistId";
}
diff --git a/src/main/java/com/botdarr/api/lidarr/LidarrArtist.java b/src/main/java/com/botdarr/api/lidarr/LidarrArtist.java
index c87a004..9a017de 100644
--- a/src/main/java/com/botdarr/api/lidarr/LidarrArtist.java
+++ b/src/main/java/com/botdarr/api/lidarr/LidarrArtist.java
@@ -1,6 +1,8 @@
package com.botdarr.api.lidarr;
import com.botdarr.api.KeyBased;
+import com.botdarr.api.sonarr.SonarrImage;
+import org.apache.logging.log4j.util.Strings;
import java.util.List;
@@ -102,6 +104,22 @@ public String getRemotePoster() {
return remotePoster;
}
+ public String getRemoteImage() {
+ if (Strings.isEmpty(remotePoster)) {
+ for (LidarrImage lidarrImage : images) {
+ if (lidarrImage.getCoverType().equals("poster") && !Strings.isEmpty(lidarrImage.getRemoteUrl())) {
+ return lidarrImage.getRemoteUrl();
+ }
+ }
+ for (LidarrImage lidarrImage : this.lastAlbum.getImages()) {
+ if (lidarrImage.getCoverType().equals("cover") && !Strings.isEmpty(lidarrImage.getUrl())) {
+ return lidarrImage.getUrl();
+ }
+ }
+ }
+ return remotePoster;
+ }
+
public void setRemotePoster(String remotePoster) {
this.remotePoster = remotePoster;
}
@@ -227,4 +245,5 @@ public void setPath(String path) {
private LidarrAddOptions addOptions = new LidarrAddOptions();
private String rootFolderPath;
private String path;
+ private LidarrAlbum lastAlbum = new LidarrAlbum();
}
diff --git a/src/main/java/com/botdarr/api/lidarr/LidarrCommands.java b/src/main/java/com/botdarr/api/lidarr/LidarrCommands.java
index 2183dff..39e0b7f 100644
--- a/src/main/java/com/botdarr/api/lidarr/LidarrCommands.java
+++ b/src/main/java/com/botdarr/api/lidarr/LidarrCommands.java
@@ -1,31 +1,33 @@
package com.botdarr.api.lidarr;
+import com.botdarr.Config;
import com.botdarr.api.ContentType;
import com.botdarr.api.lidarr.LidarrApi;
-import com.botdarr.commands.BaseCommand;
-import com.botdarr.commands.Command;
-import com.botdarr.commands.CommandProcessor;
-import com.botdarr.commands.CommandResponseUtil;
+import com.botdarr.commands.*;
import com.botdarr.commands.responses.CommandResponse;
import com.botdarr.commands.responses.InfoResponse;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class LidarrCommands {
public static List getCommands(LidarrApi lidarrApi) {
return new ArrayList() {{
- add(new BaseCommand("music artist add", "music artist add ",
- "Adds an artist using search text (i.e., music add Dre Fudgington)") {
+ add(new BaseCommand(
+ "music artist add",
+ "Adds an artist using search text (i.e., music add Dre Fudgington)",
+ Collections.singletonList("artist-name")) {
@Override
public List execute(String artistToSearch) {
return lidarrApi.addArtist(artistToSearch);
}
});
- add(new BaseCommand("music artist id add", "music artist id add ",
- "Adds an artist using lidarr artist id and artist name (i.e., music artist id add F894MN4-F84J4 Beastie Girls). The easiest" +
- " way to use this command is using the find commands to find new artists, which have the add commands or you can use thumbs reaction (in slack/discord)") {
+ add(new BaseCommand(
+ "music artist id add",
+ "Adds an artist using lidarr artist id and artist name (i.e., music artist id add F894MN4-F84J4 Beastie Girls).",
+ Arrays.asList("lidar-artist-id", "artist-name")) {
@Override
public List execute(String command) {
int lastSpace = command.lastIndexOf(" ");
@@ -37,15 +39,19 @@ public List execute(String command) {
return Collections.singletonList(lidarrApi.addArtistWithId(id, searchText));
}
});
- add(new BaseCommand("music artist find existing", "music artist find existing ",
- "Finds an existing artist using lidarr (i.e., music artist find existing ArtistA)") {
+ add(new BaseCommand(
+ "music artist find existing",
+ "Finds an existing artist using lidarr (i.e., music artist find existing ArtistA)",
+ Collections.singletonList("artist-name")) {
@Override
public List execute(String command) {
return lidarrApi.lookupArtists(command, false);
}
});
- add(new BaseCommand("music artist find new", "music artist find new ",
- "Finds a new artist using lidarr (i.e., music find new artist ArtistB)") {
+ add(new BaseCommand(
+ "music artist find new",
+ "Finds a new artist using lidarr (i.e., music find new artist ArtistB)",
+ Collections.singletonList("artist-name")) {
@Override
public List execute(String command) {
return lidarrApi.lookupArtists(command, true);
@@ -66,10 +72,10 @@ public List execute(String command) {
}
public static String getAddArtistCommandStr(String artistName, String foreignArtistId) {
- return new CommandProcessor().getPrefix() + "music artist id add " + artistName + " " + foreignArtistId;
+ return CommandContext.getConfig().getPrefix() + "music artist id add " + artistName + " " + foreignArtistId;
}
public static String getHelpCommandStr() {
- return new CommandProcessor().getPrefix() + "music help";
+ return CommandContext.getConfig().getPrefix() + "music help";
}
}
diff --git a/src/main/java/com/botdarr/api/lidarr/LidarrImage.java b/src/main/java/com/botdarr/api/lidarr/LidarrImage.java
index c9b1a0d..e56634c 100644
--- a/src/main/java/com/botdarr/api/lidarr/LidarrImage.java
+++ b/src/main/java/com/botdarr/api/lidarr/LidarrImage.java
@@ -17,6 +17,15 @@ public void setUrl(String url) {
this.url = url;
}
+ public String getRemoteUrl() {
+ return remoteUrl;
+ }
+
+ public void setRemoteUrl(String remoteUrl) {
+ this.remoteUrl = remoteUrl;
+ }
+
private String coverType;
private String url;
+ private String remoteUrl;
}
diff --git a/src/main/java/com/botdarr/api/radarr/RadarrApi.java b/src/main/java/com/botdarr/api/radarr/RadarrApi.java
index 7d42529..ea56ef8 100644
--- a/src/main/java/com/botdarr/api/radarr/RadarrApi.java
+++ b/src/main/java/com/botdarr/api/radarr/RadarrApi.java
@@ -332,4 +332,5 @@ private boolean isPathBlacklisted(RadarrMovie item) {
private static RadarrCache RADARR_CACHE = new RadarrCache();
public static final String ADD_MOVIE_COMMAND_FIELD_PREFIX = "Add movie command";
+ public static final String MOVIE_LOOKUP_FIELD = "TmdbId";
}
diff --git a/src/main/java/com/botdarr/api/radarr/RadarrCommands.java b/src/main/java/com/botdarr/api/radarr/RadarrCommands.java
index cac927f..191f30d 100644
--- a/src/main/java/com/botdarr/api/radarr/RadarrCommands.java
+++ b/src/main/java/com/botdarr/api/radarr/RadarrCommands.java
@@ -1,14 +1,12 @@
package com.botdarr.api.radarr;
import com.botdarr.api.ContentType;
-import com.botdarr.commands.BaseCommand;
-import com.botdarr.commands.Command;
-import com.botdarr.commands.CommandProcessor;
-import com.botdarr.commands.CommandResponseUtil;
+import com.botdarr.commands.*;
import com.botdarr.commands.responses.CommandResponse;
import org.apache.logging.log4j.util.Strings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -26,8 +24,10 @@ public List execute(String command) {
return radarrApi.discover();
}
});
- add(new BaseCommand("movie id add", "movie id add ", "Adds a movie using search text and tmdb id (i.e., movie id add John Wick 484737). The easiest" +
- " way to use this command is to use \"movie find new TITLE\", then the results will contain the movie add command for you") {
+ add(new BaseCommand(
+ "movie id add",
+ "Adds a movie using search text and tmdb id (i.e., movie id add John Wick 484737).",
+ Arrays.asList("movie-title", "movie-tmdbid")) {
@Override
public List execute(String command) {
int lastSpace = command.lastIndexOf(" ");
@@ -41,8 +41,10 @@ public List execute(String command) {
return Collections.singletonList(radarrApi.addWithId(searchText, id));
}
});
- add(new BaseCommand("movie title add", "movie title add ", "Adds a movie with just a title. Since many movies can have same title or very similar titles, the trakt" +
- " search can return multiple movies, if we detect multiple new films, we will return those films, otherwise we will add the single film.") {
+ add(new BaseCommand(
+ "movie title add",
+ "Adds a movie with just a title. Since many movies can have same title or very similar titles",
+ Collections.singletonList("movie-title")) {
@Override
public List execute(String searchText) {
validateMovieTitle(searchText);
@@ -60,14 +62,20 @@ public List execute(String command) {
return radarrApi.getProfiles();
}
});
- add(new BaseCommand("movie find new", "movie find new ", "Finds a new movie using radarr (i.e., movie find new John Wick)") {
+ add(new BaseCommand(
+ "movie find new",
+ "Finds a new movie using radarr (i.e., movie find new John Wick)",
+ Collections.singletonList("movie-title")) {
@Override
public List execute(String searchText) {
validateMovieTitle(searchText);
return radarrApi.lookup(searchText, true);
}
});
- add(new BaseCommand("movie find existing", "movie find existing ", "Finds an existing movie using radarr (i.e., movie find existing Princess Fudgecake)") {
+ add(new BaseCommand(
+ "movie find existing",
+ "Finds an existing movie using radarr (i.e., movie find existing Princess Fudgecake)",
+ Collections.singletonList("movie-title")) {
@Override
public List execute(String searchText) {
validateMovieTitle(searchText);
@@ -89,11 +97,11 @@ public List execute(String command) {
}
public static String getAddMovieCommandStr(String title, long tmdbId) {
- return new CommandProcessor().getPrefix() + "movie id add " + title + " " + tmdbId;
+ return CommandContext.getConfig().getPrefix() + "movie id add " + title + " " + tmdbId;
}
public static String getHelpMovieCommandStr() {
- return new CommandProcessor().getPrefix() + "movies help";
+ return CommandContext.getConfig().getPrefix() + "movies help";
}
private static void validateMovieTitle(String movieTitle) {
diff --git a/src/main/java/com/botdarr/api/radarr/RadarrMovie.java b/src/main/java/com/botdarr/api/radarr/RadarrMovie.java
index 4dbd1a2..009d95f 100644
--- a/src/main/java/com/botdarr/api/radarr/RadarrMovie.java
+++ b/src/main/java/com/botdarr/api/radarr/RadarrMovie.java
@@ -1,6 +1,7 @@
package com.botdarr.api.radarr;
import com.botdarr.api.KeyBased;
+import org.apache.logging.log4j.util.Strings;
import java.util.Date;
import java.util.List;
@@ -90,7 +91,18 @@ public void setWebsite(String website) {
this.website = website;
}
- public String getRemotePoster() {
+ public String getRemoteImage() {
+ if (Strings.isEmpty(remotePoster)) {
+ for(RadarrImage radarrImage : images) {
+ if (radarrImage.getCoverType().equals("poster") && !Strings.isEmpty(radarrImage.getRemoteUrl())) {
+ return radarrImage.getRemoteUrl();
+ }
+ }
+ }
+ return remotePoster;
+ }
+
+ public String getRemotePost() {
return remotePoster;
}
diff --git a/src/main/java/com/botdarr/api/sonarr/SonarrApi.java b/src/main/java/com/botdarr/api/sonarr/SonarrApi.java
index be2823b..6405db7 100644
--- a/src/main/java/com/botdarr/api/sonarr/SonarrApi.java
+++ b/src/main/java/com/botdarr/api/sonarr/SonarrApi.java
@@ -282,4 +282,5 @@ private boolean isPathBlacklisted(SonarrShow item) {
private static final SonarrCache SONARR_CACHE = new SonarrCache();
public static final String ADD_SHOW_COMMAND_FIELD_PREFIX = "Add show command";
+ public static final String SHOW_LOOKUP_FIELD = "TvdbId";
}
diff --git a/src/main/java/com/botdarr/api/sonarr/SonarrCommands.java b/src/main/java/com/botdarr/api/sonarr/SonarrCommands.java
index e589e0e..9701aac 100644
--- a/src/main/java/com/botdarr/api/sonarr/SonarrCommands.java
+++ b/src/main/java/com/botdarr/api/sonarr/SonarrCommands.java
@@ -1,23 +1,22 @@
package com.botdarr.api.sonarr;
import com.botdarr.api.ContentType;
-import com.botdarr.commands.BaseCommand;
-import com.botdarr.commands.Command;
-import com.botdarr.commands.CommandProcessor;
-import com.botdarr.commands.CommandResponseUtil;
+import com.botdarr.commands.*;
import com.botdarr.commands.responses.CommandResponse;
import org.apache.logging.log4j.util.Strings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SonarrCommands {
public static List getCommands(SonarrApi sonarrApi) {
return new ArrayList() {{
- add(new BaseCommand("show id add", "show id add ",
- "Adds a show using search text and tmdb id (i.e., show id add 30 rock 484737). The easiest" +
- " way to use this command is to use \"show find new \", then the results will contain the show add command for you") {
+ add(new BaseCommand(
+ "show id add",
+ "Adds a show using search text and tmdb id (i.e., show id add 30 clock 484767)",
+ Arrays.asList("show-title", "show-tvdbid")) {
@Override
public List execute(String command) {
int lastSpace = command.lastIndexOf(" ");
@@ -31,9 +30,10 @@ public List execute(String command) {
return Collections.singletonList(sonarrApi.addWithId(searchText, id));
}
});
- add(new BaseCommand("show title add", "show title add ",
- "Adds a show with just a title. Since there can be multiple shows that match search criteria" +
- " we will either add the show or return all the shows that match your search.") {
+ add(new BaseCommand(
+ "show title add",
+ "Adds a show with just a title.",
+ Collections.singletonList("show-title")) {
@Override
public List execute(String command) {
validateShowTitle(command);
@@ -62,14 +62,20 @@ public List execute(String command) {
return sonarrApi.getProfiles();
}
});
- add(new BaseCommand("show find existing", "show find existing ", "Finds a existing show using sonarr (i.e., show find existing Ahh! Real fudgecakes)") {
+ add(new BaseCommand(
+ "show find existing",
+ "Finds a existing show using sonarr (i.e., show find existing Ahh! Real fudgecakes)",
+ Collections.singletonList("show-title")) {
@Override
public List execute(String command) {
validateShowTitle(command);
return sonarrApi.lookup(command, false);
}
});
- add(new BaseCommand("show find new", "show find new ", "Finds a new show using sonarr (i.e., show find new Fresh Prince of Fresh air)") {
+ add(new BaseCommand(
+ "show find new",
+ "Finds a new show using sonarr (i.e., show find new Fresh Prince of Fresh air)",
+ Collections.singletonList("show-title")) {
@Override
public List execute(String command) {
validateShowTitle(command);
@@ -80,11 +86,11 @@ public List execute(String command) {
}
public static String getAddShowCommandStr(String title, long tvdbId) {
- return new CommandProcessor().getPrefix() + "show id add " + title + " " + tvdbId;
+ return CommandContext.getConfig().getPrefix() + "show id add " + title + " " + tvdbId;
}
public static String getHelpShowCommandStr() {
- return new CommandProcessor().getPrefix() + "shows help";
+ return CommandContext.getConfig().getPrefix() + "shows help";
}
private static void validateShowTitle(String movieTitle) {
diff --git a/src/main/java/com/botdarr/api/sonarr/SonarrImage.java b/src/main/java/com/botdarr/api/sonarr/SonarrImage.java
index c54bae7..4391354 100644
--- a/src/main/java/com/botdarr/api/sonarr/SonarrImage.java
+++ b/src/main/java/com/botdarr/api/sonarr/SonarrImage.java
@@ -17,6 +17,15 @@ public void setUrl(String url) {
this.url = url;
}
+ public String getRemoteUrl() {
+ return remoteUrl;
+ }
+
+ public void setRemoteUrl(String remoteUrl) {
+ this.remoteUrl = remoteUrl;
+ }
+
private String coverType;
private String url;
+ private String remoteUrl;
}
diff --git a/src/main/java/com/botdarr/api/sonarr/SonarrShow.java b/src/main/java/com/botdarr/api/sonarr/SonarrShow.java
index dfe85cd..1402f9c 100644
--- a/src/main/java/com/botdarr/api/sonarr/SonarrShow.java
+++ b/src/main/java/com/botdarr/api/sonarr/SonarrShow.java
@@ -1,6 +1,8 @@
package com.botdarr.api.sonarr;
import com.botdarr.api.KeyBased;
+import com.botdarr.api.radarr.RadarrImage;
+import org.apache.logging.log4j.util.Strings;
import java.util.List;
@@ -74,6 +76,17 @@ public String getRemotePoster() {
return remotePoster;
}
+ public String getRemoteImage() {
+ if (Strings.isEmpty(remotePoster)) {
+ for(SonarrImage sonarrImage : images) {
+ if (sonarrImage.getCoverType().equals("poster") && !Strings.isEmpty(sonarrImage.getRemoteUrl())) {
+ return sonarrImage.getRemoteUrl();
+ }
+ }
+ }
+ return remotePoster;
+ }
+
public void setRemotePoster(String remotePoster) {
this.remotePoster = remotePoster;
}
diff --git a/src/main/java/com/botdarr/clients/ChatClientBootstrap.java b/src/main/java/com/botdarr/clients/ChatClientBootstrap.java
index 0a70628..6128217 100644
--- a/src/main/java/com/botdarr/clients/ChatClientBootstrap.java
+++ b/src/main/java/com/botdarr/clients/ChatClientBootstrap.java
@@ -8,7 +8,6 @@
import com.botdarr.api.radarr.RadarrCommands;
import com.botdarr.api.sonarr.SonarrApi;
import com.botdarr.api.sonarr.SonarrCommands;
-import com.botdarr.clients.telegram.TelegramResponse;
import com.botdarr.commands.*;
import com.botdarr.commands.responses.CommandResponse;
import com.botdarr.scheduling.Scheduler;
@@ -26,7 +25,7 @@ public void validatePrefix(String configuredPrefix) {
}
}
- protected static ApisAndCommandConfig buildConfig() {
+ protected ApisAndCommandConfig buildConfig() {
RadarrApi radarrApi = new RadarrApi();
SonarrApi sonarrApi = new SonarrApi();
LidarrApi lidarrApi = new LidarrApi();
@@ -63,20 +62,31 @@ protected void initScheduling(ChatClient chatC
scheduler.initApiNotifications(apis, chatClient, responseBuilder);
}
- protected static void runAndProcessCommands(String message,
- String username,
- ChatClientResponseBuilder responseBuilder,
- ChatSender chatSender) {
- List commandResponses =
- commandProcessor.processRequestMessage(buildConfig().getCommands(), message, username);
- if (commandResponses != null) {
- //if there is a response, format it for given response builder
- for (CommandResponse commandResponse : commandResponses) {
- //convert command response into chat client specific response
- T telegramResponse = commandResponse.convertToChatClientResponse(responseBuilder);
- //then send the response
- chatSender.send(telegramResponse);
+ protected void runAndProcessCommands(String prefix,
+ String message,
+ String username,
+ ChatClientResponseBuilder responseBuilder,
+ ChatSender chatSender) {
+ try {
+ CommandContext
+ .start()
+ .setPrefix(prefix)
+ .setUsername(username);
+ LOGGER.debug("Processing command " + message + " for username " + username + " with prefix " + prefix);
+ List commandResponses =
+ commandProcessor.processCommand(prefix, buildConfig().getCommands(), message, username);
+ if (commandResponses != null) {
+ //if there is a response, format it for given response builder
+ for (CommandResponse commandResponse : commandResponses) {
+ LOGGER.debug("Processing command response " + commandResponse.toString());
+ //convert command response into chat client specific response
+ T clientResponse = commandResponse.convertToChatClientResponse(responseBuilder);
+ //then send the response
+ chatSender.send(clientResponse);
+ }
}
+ } finally {
+ CommandContext.end();
}
}
@@ -98,6 +108,6 @@ public List getCommands() {
private final List commands;
}
- protected static CommandProcessor commandProcessor = new CommandProcessor();
+ protected CommandProcessor commandProcessor = new CommandProcessor();
protected static final Logger LOGGER = LogManager.getLogger(ChatClientBootstrap.class);
}
diff --git a/src/main/java/com/botdarr/clients/discord/DiscordBootstrap.java b/src/main/java/com/botdarr/clients/discord/DiscordBootstrap.java
index 5a06447..4e37af0 100644
--- a/src/main/java/com/botdarr/clients/discord/DiscordBootstrap.java
+++ b/src/main/java/com/botdarr/clients/discord/DiscordBootstrap.java
@@ -1,30 +1,47 @@
package com.botdarr.clients.discord;
import com.botdarr.Config;
+import com.botdarr.api.lidarr.LidarrCommands;
+import com.botdarr.api.radarr.RadarrCommands;
+import com.botdarr.api.sonarr.SonarrCommands;
import com.botdarr.clients.ChatClient;
import com.botdarr.clients.ChatClientBootstrap;
import com.botdarr.clients.ChatClientResponseBuilder;
+import com.botdarr.commands.Command;
+import com.botdarr.commands.CommandContext;
import com.botdarr.scheduling.Scheduler;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.MessageHistory;
+import net.dv8tion.jda.api.entities.MessageType;
import net.dv8tion.jda.api.events.GenericEvent;
import net.dv8tion.jda.api.events.ReadyEvent;
+import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
+import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import net.dv8tion.jda.api.interactions.commands.OptionMapping;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.CommandData;
+import net.dv8tion.jda.api.requests.restaction.WebhookMessageAction;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.util.Strings;
+import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
+import java.util.Collections;
import java.util.List;
import java.util.Properties;
import static com.botdarr.api.lidarr.LidarrApi.ADD_ARTIST_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.lidarr.LidarrApi.ARTIST_LOOKUP_KEY_FIELD;
import static com.botdarr.api.radarr.RadarrApi.ADD_MOVIE_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.radarr.RadarrApi.MOVIE_LOOKUP_FIELD;
import static com.botdarr.api.sonarr.SonarrApi.ADD_SHOW_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.sonarr.SonarrApi.SHOW_LOOKUP_FIELD;
public class DiscordBootstrap extends ChatClientBootstrap {
@Override
@@ -48,6 +65,43 @@ public void onReady(@Nonnull ReadyEvent event) {
super.onReady(event);
}
+ @Override
+ public void onSlashCommand(@NotNull SlashCommandEvent event) {
+ // let discord know we received the message as quick as we can
+ event.deferReply().queue();
+
+ String discordSlashCommandPrefix = "/";
+ StringBuilder eventCommand = new StringBuilder(discordSlashCommandPrefix + event.getName().replace('-', ' '));
+ for (OptionMapping option : event.getOptions()) {
+ eventCommand.append(" ").append(option.getAsString());
+ }
+ ChatClientResponseBuilder slashCommandResponseBuilder = new DiscordResponseBuilder().usesSlashCommands();
+ //capture/process command
+ Scheduler.getScheduler().executeCommand(() -> {
+ runAndProcessCommands(discordSlashCommandPrefix, eventCommand.toString(), event.getUser().getName(), slashCommandResponseBuilder, chatClientResponse -> {
+ // then send the rest of the messages
+ WebhookMessageAction action = event.getHook().sendMessageEmbeds(Collections.singletonList(chatClientResponse.getMessage()));
+ if (!chatClientResponse.getActionComponents().isEmpty()) {
+ action = action.addActionRow(chatClientResponse.getActionComponents());
+ }
+ action.queue();
+ });
+ return null;
+ });
+ LogManager.getLogger("com.botdarr.clients.discord").debug(eventCommand);
+ }
+
+ @Override
+ public void onButtonClick(@NotNull ButtonClickEvent event) {
+ Message message = event.getInteraction().getMessage();
+ message.getEmbeds().forEach(embed -> {
+ String command = getCommandFromEmbed(embed);
+ if (!Strings.isEmpty(command)) {
+ handleCommand(event.getJDA(), command, event.getUser().getName(), event.getChannel().getName());
+ }
+ });
+ }
+
@Override
public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) {
if (event.getReactionEmote().getName().equalsIgnoreCase(THUMBS_UP_EMOTE)) {
@@ -78,8 +132,10 @@ public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent even
@Override
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
- handleCommand(event.getJDA(), event.getMessage().getContentStripped(), event.getAuthor().getName(), event.getChannel().getName());
- LogManager.getLogger("com.botdarr.clients.discord").debug(event.getMessage().getContentRaw());
+ if (event.getMessage().getType() != MessageType.APPLICATION_COMMAND && event.getMessage().getEmbeds().isEmpty()) {
+ handleCommand(event.getJDA(), event.getMessage().getContentStripped(), event.getAuthor().getName(), event.getChannel().getName());
+ LogManager.getLogger("com.botdarr.clients.discord").debug(event.getMessage().getContentRaw());
+ }
super.onMessageReceived(event);
}
@@ -89,7 +145,7 @@ private void handleCommand(JDA jda, String message, String author, String channe
//capture/process command
Scheduler.getScheduler().executeCommand(() -> {
- runAndProcessCommands(message, author, responseBuilder, chatClientResponse -> {
+ DiscordBootstrap.this.runAndProcessCommands(CommandContext.getConfig().getPrefix(), message, author, responseBuilder, chatClientResponse -> {
discordChatClient.sendMessage(chatClientResponse, channelName);
});
return null;
@@ -98,6 +154,7 @@ private void handleCommand(JDA jda, String message, String author, String channe
private static final String THUMBS_UP_EMOTE = "\uD83D\uDC4D";
}).build();
+ config.getCommands().forEach(command -> jda.upsertCommand(convertCommandToCommandData(command)).queue());
jda.awaitReady();
} catch (Throwable e) {
LogManager.getLogger("com.botdarr.clients.discord").error("Error caught during main", e);
@@ -110,4 +167,43 @@ public boolean isConfigured(Properties properties) {
return !Strings.isBlank(properties.getProperty(Config.Constants.DISCORD_TOKEN)) &&
!Strings.isBlank(properties.getProperty(Config.Constants.DISCORD_CHANNELS));
}
+
+ @Override
+ public void validatePrefix(String configuredPrefix) {
+ super.validatePrefix(configuredPrefix);
+ if (configuredPrefix.equals("/")) {
+ throw new RuntimeException("Cannot use / command prefix in discord since / command is used by discord slash commands");
+ }
+ }
+
+ public String getCommandFromEmbed(MessageEmbed embed) {
+ for(MessageEmbed.Field field : embed.getFields()) {
+ if (field.getName() != null) {
+ if (field.getName().equals(MOVIE_LOOKUP_FIELD)) {
+ return RadarrCommands.getAddMovieCommandStr(embed.getTitle(), Long.parseLong(field.getValue()));
+ }
+ if (field.getName().equals(SHOW_LOOKUP_FIELD)) {
+ return SonarrCommands.getAddShowCommandStr(embed.getTitle(), Long.parseLong(field.getValue()));
+ }
+ if (field.getName().equals(ARTIST_LOOKUP_KEY_FIELD)) {
+ return LidarrCommands.getAddArtistCommandStr(embed.getTitle(), field.getValue());
+ }
+ }
+ }
+ return null;
+ }
+
+ public CommandData convertCommandToCommandData(Command command) {
+ String description = command.getDescription();
+ if (description.length() > 100) {
+ description = description.substring(0, 97);
+ description += "...";
+ }
+ CommandData commandData = new CommandData(command.getCommandText().replace(' ', '-'), description);
+ command.getInput().forEach(input -> {
+ // all input is required by default
+ commandData.addOption(OptionType.STRING, input, input, true);
+ });
+ return commandData;
+ }
}
diff --git a/src/main/java/com/botdarr/clients/discord/DiscordResponse.java b/src/main/java/com/botdarr/clients/discord/DiscordResponse.java
index cc3e473..ab31615 100644
--- a/src/main/java/com/botdarr/clients/discord/DiscordResponse.java
+++ b/src/main/java/com/botdarr/clients/discord/DiscordResponse.java
@@ -2,15 +2,29 @@
import com.botdarr.clients.ChatClientResponse;
import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.interactions.components.Component;
+
+import java.util.ArrayList;
+import java.util.List;
public class DiscordResponse implements ChatClientResponse {
public DiscordResponse(MessageEmbed message) {
this.message = message;
}
+ public DiscordResponse(MessageEmbed message, List actionComponents) {
+ this(message);
+ this.actionComponents = actionComponents;
+ }
+
public MessageEmbed getMessage() {
return message;
}
+ public List getActionComponents() {
+ return actionComponents;
+ }
+
+ private List actionComponents = new ArrayList<>();
private final MessageEmbed message;
}
diff --git a/src/main/java/com/botdarr/clients/discord/DiscordResponseBuilder.java b/src/main/java/com/botdarr/clients/discord/DiscordResponseBuilder.java
index f4de1a0..b73b596 100644
--- a/src/main/java/com/botdarr/clients/discord/DiscordResponseBuilder.java
+++ b/src/main/java/com/botdarr/clients/discord/DiscordResponseBuilder.java
@@ -13,16 +13,22 @@
import com.botdarr.utilities.ListUtils;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.interactions.components.Button;
+import net.dv8tion.jda.api.interactions.components.Component;
import org.apache.logging.log4j.util.Strings;
import java.awt.*;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.botdarr.api.lidarr.LidarrApi.ADD_ARTIST_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.lidarr.LidarrApi.ARTIST_LOOKUP_KEY_FIELD;
import static com.botdarr.api.radarr.RadarrApi.ADD_MOVIE_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.radarr.RadarrApi.MOVIE_LOOKUP_FIELD;
import static com.botdarr.api.sonarr.SonarrApi.ADD_SHOW_COMMAND_FIELD_PREFIX;
+import static com.botdarr.api.sonarr.SonarrApi.SHOW_LOOKUP_FIELD;
import static com.botdarr.commands.StatusCommand.STATUS_COMMAND;
import static com.botdarr.commands.StatusCommand.STATUS_COMMAND_DESCRIPTION;
import static net.dv8tion.jda.api.entities.MessageEmbed.VALUE_MAX_LENGTH;
@@ -41,22 +47,22 @@ public DiscordResponse build(HelpResponse helpResponse) {
boolean sonarrEnabled = Config.isSonarrEnabled();
boolean lidarrEnabled = Config.isLidarrEnabled();
if (radarrEnabled) {
- embedBuilder.addField(RadarrCommands.getHelpMovieCommandStr(), "Shows all the commands for movies", false);
+ embedBuilder.addField(RadarrCommands.getHelpMovieCommandStr().replace(" ", "-"), "Shows all the commands for movies", false);
}
if (sonarrEnabled) {
- embedBuilder.addField(SonarrCommands.getHelpShowCommandStr(), "Shows all the commands for shows", false);
+ embedBuilder.addField(SonarrCommands.getHelpShowCommandStr().replace(" ", "-"), "Shows all the commands for shows", false);
}
if (lidarrEnabled) {
- embedBuilder.addField(LidarrCommands.getHelpCommandStr(), "Shows all the commands for music", false);
+ embedBuilder.addField(LidarrCommands.getHelpCommandStr().replace(" ", "-"), "Shows all the commands for music", false);
}
if (!radarrEnabled && !sonarrEnabled && !lidarrEnabled) {
embedBuilder.appendDescription("No radarr or sonarr or lidarr commands configured, check your properties file and logs");
}
if (!Config.getStatusEndpoints().isEmpty()) {
- embedBuilder.addField(new CommandProcessor().getPrefix() + STATUS_COMMAND, STATUS_COMMAND_DESCRIPTION, false);
+ embedBuilder.addField(CommandContext.getConfig().getPrefix() + STATUS_COMMAND, STATUS_COMMAND_DESCRIPTION, false);
}
return new DiscordResponse(embedBuilder.build());
}
@@ -81,9 +87,9 @@ public DiscordResponse build(ShowResponse showResponse) {
EmbedBuilder embedBuilder = new EmbedBuilder();
SonarrShow show = showResponse.getShow();
embedBuilder.setTitle(show.getTitle());
- embedBuilder.addField("TvdbId", String.valueOf(show.getTvdbId()), false);
+ embedBuilder.addField(SHOW_LOOKUP_FIELD, String.valueOf(show.getTvdbId()), false);
embedBuilder.addField(ADD_SHOW_COMMAND_FIELD_PREFIX, SonarrCommands.getAddShowCommandStr(show.getTitle(), show.getTvdbId()), false);
- embedBuilder.setImage(show.getRemotePoster());
+ embedBuilder.setImage(show.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -94,7 +100,7 @@ public DiscordResponse build(MusicArtistResponse musicArtistResponse) {
embedBuilder.setTitle(lidarrArtist.getArtistName());
embedBuilder.addField("Id", String.valueOf(lidarrArtist.getForeignArtistId()), false);
embedBuilder.addField(ADD_ARTIST_COMMAND_FIELD_PREFIX, LidarrCommands.getAddArtistCommandStr(lidarrArtist.getArtistName(), lidarrArtist.getForeignArtistId()), false);
- embedBuilder.setImage(lidarrArtist.getRemotePoster());
+ embedBuilder.setImage(lidarrArtist.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -204,9 +210,14 @@ public DiscordResponse build(NewShowResponse newShowResponse) {
SonarrShow sonarrShow = newShowResponse.getNewShow();
embedBuilder.setTitle(sonarrShow.getTitle());
embedBuilder.addField("TvdbId", "" + sonarrShow.getTvdbId(), true);
- embedBuilder.addField(ADD_SHOW_COMMAND_FIELD_PREFIX, SonarrCommands.getAddShowCommandStr(sonarrShow.getTitle(), sonarrShow.getTvdbId()), false);
- embedBuilder.setImage(sonarrShow.getRemotePoster());
- return new DiscordResponse(embedBuilder.build());
+ embedBuilder.setImage(sonarrShow.getRemoteImage());
+ if (!usingSlashCommand) {
+ embedBuilder.addField(ADD_SHOW_COMMAND_FIELD_PREFIX, SonarrCommands.getAddShowCommandStr(sonarrShow.getTitle(), sonarrShow.getTvdbId()), false);
+ return new DiscordResponse(embedBuilder.build());
+ }
+ List actionComponents = new ArrayList<>();
+ actionComponents.add(Button.primary("add", "Add"));
+ return new DiscordResponse(embedBuilder.build(), actionComponents);
}
@Override
@@ -224,7 +235,7 @@ public DiscordResponse build(ExistingShowResponse existingShowResponse) {
",Available Epsiodes=" + sonarrSeason.getStatistics().getEpisodeCount() + ",Total Epsiodes=" + sonarrSeason.getStatistics().getTotalEpisodeCount(), false);
}
}
- embedBuilder.setImage(existingShow.getRemotePoster());
+ embedBuilder.setImage(existingShow.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -233,10 +244,15 @@ public DiscordResponse build(NewMovieResponse newMovieResponse) {
EmbedBuilder embedBuilder = new EmbedBuilder();
RadarrMovie radarrMovie = newMovieResponse.getRadarrMovie();
embedBuilder.setTitle(radarrMovie.getTitle());
- embedBuilder.addField("TmdbId", String.valueOf(radarrMovie.getTmdbId()), false);
- embedBuilder.addField(ADD_MOVIE_COMMAND_FIELD_PREFIX, RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()), false);
- embedBuilder.setImage(radarrMovie.getRemotePoster());
- return new DiscordResponse(embedBuilder.build());
+ embedBuilder.addField(MOVIE_LOOKUP_FIELD, String.valueOf(radarrMovie.getTmdbId()), false);
+ embedBuilder.setImage(radarrMovie.getRemoteImage());
+ if (!usingSlashCommand) {
+ embedBuilder.addField(ADD_MOVIE_COMMAND_FIELD_PREFIX, RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()), false);
+ return new DiscordResponse(embedBuilder.build());
+ }
+ List actionComponents = new ArrayList<>();
+ actionComponents.add(Button.primary("add", "Add"));
+ return new DiscordResponse(embedBuilder.build(), actionComponents);
}
@Override
@@ -248,7 +264,7 @@ public DiscordResponse build(ExistingMovieResponse existingMovieResponse) {
embedBuilder.addField("Id", String.valueOf(radarrMovie.getId()), false);
embedBuilder.addField("Downloaded", String.valueOf((radarrMovie.getSizeOnDisk() > 0)), false);
embedBuilder.addField("Has File", String.valueOf(radarrMovie.isHasFile()), false);
- embedBuilder.setImage(radarrMovie.getRemotePoster());
+ embedBuilder.setImage(radarrMovie.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -258,9 +274,15 @@ public DiscordResponse build(NewMusicArtistResponse newMusicArtistResponse) {
LidarrArtist lookupArtist = newMusicArtistResponse.getLidarrArtist();
String artistDetail = " (" + lookupArtist.getDisambiguation() + ")";
embedBuilder.setTitle(lookupArtist.getArtistName() + (Strings.isEmpty(lookupArtist.getDisambiguation()) ? "" : artistDetail));
- embedBuilder.addField(ADD_ARTIST_COMMAND_FIELD_PREFIX, LidarrCommands.getAddArtistCommandStr(lookupArtist.getArtistName(), lookupArtist.getForeignArtistId()), false);
- embedBuilder.setImage(lookupArtist.getRemotePoster());
- return new DiscordResponse(embedBuilder.build());
+ embedBuilder.addField(ARTIST_LOOKUP_KEY_FIELD, lookupArtist.getForeignArtistId(), false);
+ embedBuilder.setImage(lookupArtist.getRemoteImage());
+ if (!usingSlashCommand) {
+ embedBuilder.addField(ADD_ARTIST_COMMAND_FIELD_PREFIX, LidarrCommands.getAddArtistCommandStr(lookupArtist.getArtistName(), lookupArtist.getForeignArtistId()), false);
+ return new DiscordResponse(embedBuilder.build());
+ }
+ List actionComponents = new ArrayList<>();
+ actionComponents.add(Button.primary("add", "Add"));
+ return new DiscordResponse(embedBuilder.build(), actionComponents);
}
@Override
@@ -269,7 +291,7 @@ public DiscordResponse build(ExistingMusicArtistResponse existingMusicArtistResp
LidarrArtist lookupArtist = existingMusicArtistResponse.getLidarrArtist();
String artistDetail = " (" + lookupArtist.getDisambiguation() + ")";
embedBuilder.setTitle(lookupArtist.getArtistName() + (Strings.isEmpty(lookupArtist.getDisambiguation()) ? "" : artistDetail));
- embedBuilder.setImage(lookupArtist.getRemotePoster());
+ embedBuilder.setImage(lookupArtist.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -313,7 +335,7 @@ private DiscordResponse getMovieResponse(RadarrMovie radarrMovie) {
embedBuilder.setTitle(radarrMovie.getTitle());
embedBuilder.addField("TmdbId", "" + radarrMovie.getTmdbId(), false);
embedBuilder.addField(ADD_MOVIE_COMMAND_FIELD_PREFIX, RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()), false);
- embedBuilder.setImage(radarrMovie.getRemotePoster());
+ embedBuilder.setImage(radarrMovie.getRemoteImage());
return new DiscordResponse(embedBuilder.build());
}
@@ -341,8 +363,15 @@ private DiscordResponse getListOfCommands(List commands) {
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle("Commands");
for (Command com : commands) {
- embedBuilder.addField(new CommandProcessor().getPrefix() + com.getCommandUsage(), com.getDescription(), false);
+ embedBuilder.addField(CommandContext.getConfig().getPrefix().replace(" ", "-") + com.getCommandUsage(), com.getDescription(), false);
}
return new DiscordResponse(embedBuilder.build());
}
+
+ public DiscordResponseBuilder usesSlashCommands() {
+ this.usingSlashCommand = true;
+ return this;
+ }
+
+ private boolean usingSlashCommand = false;
}
diff --git a/src/main/java/com/botdarr/clients/matrix/MatrixBootstrap.java b/src/main/java/com/botdarr/clients/matrix/MatrixBootstrap.java
index 8625f76..4438c2b 100644
--- a/src/main/java/com/botdarr/clients/matrix/MatrixBootstrap.java
+++ b/src/main/java/com/botdarr/clients/matrix/MatrixBootstrap.java
@@ -3,6 +3,7 @@
import com.botdarr.Config;
import com.botdarr.clients.ChatClientResponseBuilder;
import com.botdarr.clients.ChatClientBootstrap;
+import com.botdarr.commands.CommandContext;
import com.botdarr.scheduling.Scheduler;
import org.apache.logging.log4j.util.Strings;
@@ -18,7 +19,7 @@ public void init() throws Exception {
initScheduling(chatClient, responseChatClientResponseBuilder, config.getApis());
chatClient.addListener((roomId, sender, content) -> {
Scheduler.getScheduler().executeCommand(() -> {
- runAndProcessCommands(content, sender, responseChatClientResponseBuilder, chatClientResponse -> {
+ MatrixBootstrap.this.runAndProcessCommands(CommandContext.getConfig().getPrefix(), content, sender, responseChatClientResponseBuilder, chatClientResponse -> {
chatClient.sendMessage(chatClientResponse, roomId);
});
return null;
diff --git a/src/main/java/com/botdarr/clients/matrix/MatrixResponseBuilder.java b/src/main/java/com/botdarr/clients/matrix/MatrixResponseBuilder.java
index 3efa08f..83c003a 100644
--- a/src/main/java/com/botdarr/clients/matrix/MatrixResponseBuilder.java
+++ b/src/main/java/com/botdarr/clients/matrix/MatrixResponseBuilder.java
@@ -48,7 +48,7 @@ public MatrixResponse build(HelpResponse helpResponse) {
}
if (!Config.getStatusEndpoints().isEmpty()) {
- matrixResponse.addContent("" + new CommandProcessor().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION);
+ matrixResponse.addContent("" + CommandContext.getConfig().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION);
}
return matrixResponse;
} catch (Exception e) {
@@ -78,7 +78,7 @@ public MatrixResponse build(ShowResponse showResponse) {
matrixResponse.addContent("Title - " + show.getTitle());
matrixResponse.addContent("TvdbId - " + show.getTvdbId());
matrixResponse.addContent("" + ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(show.getTitle(), show.getTvdbId()));
- matrixResponse.addImage(show.getRemotePoster());
+ matrixResponse.addImage(show.getRemoteImage());
return matrixResponse;
}
@@ -222,7 +222,7 @@ public MatrixResponse build(NewShowResponse newShowResponse) {
matrixResponse.addContent("Title - " + sonarrShow.getTitle());
matrixResponse.addContent("TvdbId - " + sonarrShow.getTvdbId());
matrixResponse.addContent("" + ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(sonarrShow.getTitle(), sonarrShow.getTvdbId()));
- matrixResponse.addImage(sonarrShow.getRemotePoster());
+ matrixResponse.addImage(sonarrShow.getRemoteImage());
return matrixResponse;
}
@@ -242,7 +242,7 @@ public MatrixResponse build(ExistingShowResponse existingShowResponse) {
",Total Epsiodes=" + sonarrSeason.getStatistics().getTotalEpisodeCount());
}
}
- matrixResponse.addImage(existingShow.getRemotePoster());
+ matrixResponse.addImage(existingShow.getRemoteImage());
return matrixResponse;
}
@@ -253,7 +253,7 @@ public MatrixResponse build(NewMovieResponse newMovieResponse) {
matrixResponse.addContent("Title - " + radarrMovie.getTitle());
matrixResponse.addContent("TmdbId - " + radarrMovie.getTmdbId());
matrixResponse.addContent("" + ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()));
- matrixResponse.addImage(radarrMovie.getRemotePoster());
+ matrixResponse.addImage(radarrMovie.getRemoteImage());
return matrixResponse;
}
@@ -266,7 +266,7 @@ public MatrixResponse build(ExistingMovieResponse existingMovieResponse) {
matrixResponse.addContent("Id - " + radarrMovie.getId());
matrixResponse.addContent("Downloaded - " + (radarrMovie.getSizeOnDisk() > 0));
matrixResponse.addContent("Has File - " + radarrMovie.isHasFile());
- matrixResponse.addImage(radarrMovie.getRemotePoster());
+ matrixResponse.addImage(radarrMovie.getRemoteImage());
return matrixResponse;
}
@@ -277,7 +277,7 @@ public MatrixResponse build(NewMusicArtistResponse newMusicArtistResponse) {
String artistDetail = " (" + lidarrArtist.getDisambiguation() + ")";
matrixResponse.addContent("Title - " + (lidarrArtist.getArtistName() + (Strings.isEmpty(lidarrArtist.getDisambiguation()) ? "" : artistDetail)));
matrixResponse.addContent("" + ADD_ARTIST_COMMAND_FIELD_PREFIX + " - " + LidarrCommands.getAddArtistCommandStr(lidarrArtist.getArtistName(), lidarrArtist.getForeignArtistId()));
- matrixResponse.addImage(lidarrArtist.getRemotePoster());
+ matrixResponse.addImage(lidarrArtist.getRemoteImage());
return matrixResponse;
}
@@ -287,7 +287,7 @@ public MatrixResponse build(ExistingMusicArtistResponse existingMusicArtistRespo
MatrixResponse matrixResponse = new MatrixResponse();
String artistDetail = " (" + lidarrArtist.getDisambiguation() + ")";
matrixResponse.addContent("Title - " + (lidarrArtist.getArtistName() + (Strings.isEmpty(lidarrArtist.getDisambiguation()) ? "" : artistDetail)));
- matrixResponse.addImage(lidarrArtist.getRemotePoster());
+ matrixResponse.addImage(lidarrArtist.getRemoteImage());
return matrixResponse;
}
@@ -298,8 +298,8 @@ public MatrixResponse build(DiscoverMovieResponse discoverMovieResponse) {
matrixResponse.addContent("Title - " + radarrMovie.getTitle());
matrixResponse.addContent("TmdbId - " + radarrMovie.getTmdbId());
matrixResponse.addContent("" + ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()));
- if (radarrMovie.getRemotePoster() != null && !radarrMovie.getRemotePoster().isEmpty()) {
- matrixResponse.addImage(radarrMovie.getRemotePoster());
+ if (radarrMovie.getRemoteImage() != null && !radarrMovie.getRemoteImage().isEmpty()) {
+ matrixResponse.addImage(radarrMovie.getRemoteImage());
}
return matrixResponse;
}
@@ -327,7 +327,7 @@ private MatrixResponse getListOfCommands(List commands) {
MatrixResponse matrixResponse = new MatrixResponse();
matrixResponse.addContent("Commands");
for (Command command : commands) {
- matrixResponse.addContent("" + new CommandProcessor().getPrefix() + command.getCommandUsage() + "" + " - " + command.getDescription());
+ matrixResponse.addContent("" + CommandContext.getConfig().getPrefix() + command.getCommandUsage() + "" + " - " + command.getDescription());
}
return matrixResponse;
}
diff --git a/src/main/java/com/botdarr/clients/slack/SlackBootstrap.java b/src/main/java/com/botdarr/clients/slack/SlackBootstrap.java
index 5a21958..b536b8d 100644
--- a/src/main/java/com/botdarr/clients/slack/SlackBootstrap.java
+++ b/src/main/java/com/botdarr/clients/slack/SlackBootstrap.java
@@ -3,6 +3,7 @@
import com.botdarr.Config;
import com.botdarr.clients.ChatClientBootstrap;
import com.botdarr.clients.ChatClientResponseBuilder;
+import com.botdarr.commands.CommandContext;
import com.botdarr.scheduling.Scheduler;
import com.github.seratch.jslack.Slack;
import com.github.seratch.jslack.api.model.Message;
@@ -86,7 +87,7 @@ public void handle(String message) {
private void handleCommand(String text, String userId, String channel) {
Scheduler.getScheduler().executeCommand(() -> {
- runAndProcessCommands(text, userId, responseChatClientResponseBuilder, chatClientResponse -> {
+ SlackBootstrap.this.runAndProcessCommands(CommandContext.getConfig().getPrefix(), text, userId, responseChatClientResponseBuilder, chatClientResponse -> {
slackChatClient.sendMessage(chatClientResponse, channel);
});
return null;
diff --git a/src/main/java/com/botdarr/clients/slack/SlackResponseBuilder.java b/src/main/java/com/botdarr/clients/slack/SlackResponseBuilder.java
index a715bf4..d1b3776 100644
--- a/src/main/java/com/botdarr/clients/slack/SlackResponseBuilder.java
+++ b/src/main/java/com/botdarr/clients/slack/SlackResponseBuilder.java
@@ -72,7 +72,7 @@ public SlackResponse build(HelpResponse helpResponse) {
}
if (!Config.getStatusEndpoints().isEmpty()) {
slackResponse.addBlock(SectionBlock.builder()
- .text(MarkdownTextObject.builder().text(new CommandProcessor().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION).build())
+ .text(MarkdownTextObject.builder().text(CommandContext.getConfig().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION).build())
.build());
}
} catch (IOException e) {
@@ -109,11 +109,11 @@ public SlackResponse build(ShowResponse showResponse) {
slackResponse.addBlock(SectionBlock.builder()
.text(PlainTextObject.builder().text(ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(show.getTitle(), show.getTvdbId())).build())
.build());
- if (!Strings.isBlank(show.getRemotePoster())) {
+ if (!Strings.isBlank(show.getRemoteImage())) {
//if there is no poster to display, slack will fail to render all the blocks
//so make sure there is one before trying to render
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(show.getRemotePoster())
+ .imageUrl(show.getRemoteImage())
.altText(show.getTitle() + " poster")
.build());
}
@@ -133,11 +133,11 @@ public SlackResponse build(MusicArtistResponse musicArtistResponse) {
slackResponse.addBlock(SectionBlock.builder()
.text(PlainTextObject.builder().text(ADD_ARTIST_COMMAND_FIELD_PREFIX + " - " + LidarrCommands.getAddArtistCommandStr(lidarrArtist.getArtistName(), lidarrArtist.getForeignArtistId())).build())
.build());
- if (!Strings.isBlank(lidarrArtist.getRemotePoster())) {
+ if (!Strings.isBlank(lidarrArtist.getRemoteImage())) {
//if there is no poster to display, slack will fail to render all the blocks
//so make sure there is one before trying to render
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(lidarrArtist.getRemotePoster())
+ .imageUrl(lidarrArtist.getRemoteImage())
.altText(lidarrArtist.getArtistName() + " poster")
.build());
}
@@ -347,7 +347,7 @@ public SlackResponse build(NewShowResponse newShowResponse) {
.text(MarkdownTextObject.builder().text(ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(sonarrShow.getTitle(), sonarrShow.getTvdbId())).build())
.build());
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(sonarrShow.getRemotePoster())
+ .imageUrl(sonarrShow.getRemoteImage())
.altText(sonarrShow.getTitle() + " poster")
.build());
return slackResponse;
@@ -382,7 +382,7 @@ public SlackResponse build(ExistingShowResponse existingShowResponse) {
.build());
}
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(sonarrShow.getRemotePoster())
+ .imageUrl(sonarrShow.getRemoteImage())
.altText(sonarrShow.getTitle() + " poster")
.build());
return slackResponse;
@@ -403,7 +403,7 @@ public SlackResponse build(NewMovieResponse newMovieResponse) {
.text(MarkdownTextObject.builder().text(ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(lookupMovie.getTitle(), lookupMovie.getTmdbId())).build())
.build());
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(lookupMovie.getRemotePoster())
+ .imageUrl(lookupMovie.getRemoteImage())
.altText(lookupMovie.getTitle() + " poster")
.build());
return slackResponse;
@@ -430,7 +430,7 @@ public SlackResponse build(ExistingMovieResponse existingMovieResponse) {
.text(MarkdownTextObject.builder().text("Has File - " + lookupMovie.isHasFile()).build())
.build());
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(lookupMovie.getRemotePoster())
+ .imageUrl(lookupMovie.getRemoteImage())
.altText(lookupMovie.getTitle() + " poster")
.build());
return slackResponse;
@@ -449,7 +449,7 @@ public SlackResponse build(NewMusicArtistResponse newMusicArtistResponse) {
LidarrCommands.getAddArtistCommandStr(lookupArtist.getArtistName(), lookupArtist.getForeignArtistId())).build())
.build());
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(lookupArtist.getRemotePoster())
+ .imageUrl(lookupArtist.getRemoteImage())
.altText(lookupArtist.getArtistName() + " poster")
.build());
return slackResponse;
@@ -464,7 +464,7 @@ public SlackResponse build(ExistingMusicArtistResponse existingMusicArtistRespon
.text(MarkdownTextObject.builder().text("*Artist Name* - " + lookupArtist.getArtistName() + (Strings.isEmpty(lookupArtist.getDisambiguation()) ? "" : artistDetail)).build())
.build());
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(lookupArtist.getRemotePoster())
+ .imageUrl(lookupArtist.getRemoteImage())
.altText(lookupArtist.getArtistName() + " poster")
.build());
return slackResponse;
@@ -505,11 +505,11 @@ private SlackResponse getMovieResponse(RadarrMovie radarrMovie) {
slackResponse.addBlock(SectionBlock.builder()
.text(MarkdownTextObject.builder().text(ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId())).build())
.build());
- if (!Strings.isBlank(radarrMovie.getRemotePoster())) {
+ if (!Strings.isBlank(radarrMovie.getRemoteImage())) {
//if there is no poster to display, slack will fail to render all the blocks
//so make sure there is one before trying to render
slackResponse.addBlock(ImageBlock.builder()
- .imageUrl(radarrMovie.getRemotePoster())
+ .imageUrl(radarrMovie.getRemoteImage())
.altText(radarrMovie.getTitle() + " poster")
.build());
}
@@ -523,7 +523,7 @@ private SlackResponse getListOfCommands(List commands) {
.build());
for (Command command : commands) {
slackResponse.addBlock(SectionBlock.builder()
- .text(MarkdownTextObject.builder().text(new CommandProcessor().getPrefix() + command.getCommandUsage() + " - " + command.getDescription()).build())
+ .text(MarkdownTextObject.builder().text(CommandContext.getConfig().getPrefix() + command.getCommandUsage() + " - " + command.getDescription()).build())
.build());
}
return slackResponse;
diff --git a/src/main/java/com/botdarr/clients/telegram/TelegramBootstrap.java b/src/main/java/com/botdarr/clients/telegram/TelegramBootstrap.java
index 3945510..6a85674 100644
--- a/src/main/java/com/botdarr/clients/telegram/TelegramBootstrap.java
+++ b/src/main/java/com/botdarr/clients/telegram/TelegramBootstrap.java
@@ -3,6 +3,7 @@
import com.botdarr.Config;
import com.botdarr.clients.ChatClientBootstrap;
import com.botdarr.clients.ChatClientResponseBuilder;
+import com.botdarr.commands.CommandContext;
import com.botdarr.scheduling.Scheduler;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
@@ -37,7 +38,7 @@ public void init() throws Exception {
//for now we leave the author as "telegram" till a better solution arises
String author = "telegram";
Scheduler.getScheduler().executeCommand(() -> {
- runAndProcessCommands(text, author, responseChatClientResponseBuilder, chatClientResponse -> {
+ TelegramBootstrap.this.runAndProcessCommands(CommandContext.getConfig().getPrefix(), text, author, responseChatClientResponseBuilder, chatClientResponse -> {
telegramChatClient.sendMessage(chatClientResponse, message.chat());
});
return null;
diff --git a/src/main/java/com/botdarr/clients/telegram/TelegramResponseBuilder.java b/src/main/java/com/botdarr/clients/telegram/TelegramResponseBuilder.java
index 92fc8ca..c238f2f 100644
--- a/src/main/java/com/botdarr/clients/telegram/TelegramResponseBuilder.java
+++ b/src/main/java/com/botdarr/clients/telegram/TelegramResponseBuilder.java
@@ -50,7 +50,7 @@ public TelegramResponse build(HelpResponse helpResponse) {
domContents.add(b("*No radarr or sonarr or lidarr commands configured, check your properties file and logs*"));
}
if (!Config.getStatusEndpoints().isEmpty()) {
- domContents.add(text(new CommandProcessor().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION));
+ domContents.add(text(CommandContext.getConfig().getPrefix() + STATUS_COMMAND + " - " + STATUS_COMMAND_DESCRIPTION));
}
return new TelegramResponse(domContents);
} catch (IOException e) {
@@ -80,7 +80,7 @@ public TelegramResponse build(ShowResponse showResponse) {
domContents.add(b("*Title* - " + show.getTitle()));
domContents.add(code("TvdbId - " + show.getTvdbId()));
domContents.add(u(ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(show.getTitle(), show.getTvdbId())));
- domContents.add(a(show.getRemotePoster()));
+ domContents.add(a(show.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -91,7 +91,7 @@ public TelegramResponse build(MusicArtistResponse musicArtistResponse) {
domContents.add(b("*Artist Name* - " + lidarrArtist.getArtistName()));
domContents.add(code("Id - " + lidarrArtist.getForeignArtistId()));
domContents.add(u(ADD_ARTIST_COMMAND_FIELD_PREFIX + " - " + LidarrCommands.getAddArtistCommandStr(lidarrArtist.getArtistName(), lidarrArtist.getForeignArtistId())));
- domContents.add(a(lidarrArtist.getRemotePoster()));
+ domContents.add(a(lidarrArtist.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -233,7 +233,7 @@ public TelegramResponse build(NewShowResponse newShowResponse) {
domContents.add(b("*Title* - " + sonarrShow.getTitle()));
domContents.add(code("TvdbId - " + sonarrShow.getTvdbId()));
domContents.add(u(ADD_SHOW_COMMAND_FIELD_PREFIX + " - " + SonarrCommands.getAddShowCommandStr(sonarrShow.getTitle(), sonarrShow.getTvdbId())));
- domContents.add(a(sonarrShow.getRemotePoster()));
+ domContents.add(a(sonarrShow.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -256,7 +256,7 @@ public TelegramResponse build(ExistingShowResponse existingShowResponse) {
.append("\n");
}
domContents.add(code(existingShowDetails.toString()));
- domContents.add(a(sonarrShow.getRemotePoster()));
+ domContents.add(a(sonarrShow.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -266,7 +266,7 @@ public TelegramResponse build(NewMovieResponse newMovieResponse) {
List domContents = new ArrayList<>();
domContents.add(b(lookupMovie.getTitle()));
domContents.add(u(ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(lookupMovie.getTitle(), lookupMovie.getTmdbId())));
- domContents.add(a(lookupMovie.getRemotePoster()));
+ domContents.add(a(lookupMovie.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -279,7 +279,7 @@ public TelegramResponse build(ExistingMovieResponse existingMovieResponse) {
"Downloaded - " + (lookupMovie.getSizeOnDisk() > 0) + "\n" +
"Has File - " + lookupMovie.isHasFile() + "\n";
domContents.add(code(existingDetails));
- domContents.add(a(lookupMovie.getRemotePoster()));
+ domContents.add(a(lookupMovie.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -290,7 +290,7 @@ public TelegramResponse build(NewMusicArtistResponse newMusicArtistResponse) {
String artistDetail = " (" + lookupArtist.getDisambiguation() + ")";
domContents.add(b(lookupArtist.getArtistName() + (Strings.isEmpty(lookupArtist.getDisambiguation()) ? "" : artistDetail)));
domContents.add(u(ADD_ARTIST_COMMAND_FIELD_PREFIX + " - " + LidarrCommands.getAddArtistCommandStr(lookupArtist.getArtistName(), lookupArtist.getForeignArtistId())));
- domContents.add(a(lookupArtist.getRemotePoster()));
+ domContents.add(a(lookupArtist.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -300,7 +300,7 @@ public TelegramResponse build(ExistingMusicArtistResponse existingMusicArtistRes
List domContents = new ArrayList<>();
String artistDetail = " (" + lookupArtist.getDisambiguation() + ")";
domContents.add(b(lookupArtist.getArtistName() + (Strings.isEmpty(lookupArtist.getDisambiguation()) ? "" : artistDetail)));
- domContents.add(a(lookupArtist.getRemotePoster()));
+ domContents.add(a(lookupArtist.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -329,7 +329,7 @@ private TelegramResponse getMovieResponse(RadarrMovie radarrMovie) {
domContents.add(b(radarrMovie.getTitle()));
domContents.add(text("TmdbId - " + radarrMovie.getTmdbId()));
domContents.add(u(b(ADD_MOVIE_COMMAND_FIELD_PREFIX + " - " + RadarrCommands.getAddMovieCommandStr(radarrMovie.getTitle(), radarrMovie.getTmdbId()))));
- domContents.add(a(radarrMovie.getRemotePoster()));
+ domContents.add(a(radarrMovie.getRemoteImage()));
return new TelegramResponse(domContents);
}
@@ -337,7 +337,7 @@ private List getListOfCommands(List commands) {
List domContents = new ArrayList<>();
domContents.add(u(b("*Commands*")));
for (Command command : commands) {
- domContents.add(b(text(new CommandProcessor().getPrefix() + command.getCommandUsage())));
+ domContents.add(b(text(CommandContext.getConfig().getPrefix() + command.getCommandUsage())));
domContents.add(text(command.getDescription()));
domContents.add(text(" "));
}
diff --git a/src/main/java/com/botdarr/commands/BaseCommand.java b/src/main/java/com/botdarr/commands/BaseCommand.java
index b0e9dd0..a748ae7 100644
--- a/src/main/java/com/botdarr/commands/BaseCommand.java
+++ b/src/main/java/com/botdarr/commands/BaseCommand.java
@@ -1,16 +1,19 @@
package com.botdarr.commands;
-import com.google.common.base.Strings;
+
+import java.util.Collections;
+import java.util.List;
public abstract class BaseCommand implements Command {
public BaseCommand(String commandText, String description) {
- this(commandText, "", description);
+ this(commandText, description, Collections.emptyList());
}
- public BaseCommand(String commandText, String usageText, String description) {
+ public BaseCommand(String commandText, String description, List input) {
this.commandText = commandText;
this.description = description;
- this.usageText = usageText;
+ this.usageText = commandText + (input != null && !input.isEmpty() ? " " + String.join(" ", input) : "");
+ this.input = input;
}
@Override
@@ -30,10 +33,16 @@ public String getCommandText() {
@Override
public String getCommandUsage() {
- return Strings.isNullOrEmpty(usageText) ? getCommandText() : usageText;
+ return this.usageText;
+ }
+
+ @Override
+ public List getInput() {
+ return input;
}
private final String description;
private final String commandText;
private final String usageText;
+ private final List input;
}
diff --git a/src/main/java/com/botdarr/commands/Command.java b/src/main/java/com/botdarr/commands/Command.java
index eaa4ace..1cbbe6f 100644
--- a/src/main/java/com/botdarr/commands/Command.java
+++ b/src/main/java/com/botdarr/commands/Command.java
@@ -8,6 +8,7 @@ public interface Command {
String getCommandText();
String getDescription();
String getIdentifier();
+ List getInput();
default String getCommandUsage() {
return "";
}
diff --git a/src/main/java/com/botdarr/commands/CommandContext.java b/src/main/java/com/botdarr/commands/CommandContext.java
index 159d91a..128cc5e 100644
--- a/src/main/java/com/botdarr/commands/CommandContext.java
+++ b/src/main/java/com/botdarr/commands/CommandContext.java
@@ -1,5 +1,8 @@
package com.botdarr.commands;
+import com.botdarr.Config;
+import org.apache.logging.log4j.util.Strings;
+
public class CommandContext {
public static CommandContextConfig getConfig() {
if (contextConfigThreadLocal == null) {
@@ -25,11 +28,32 @@ public String getUsername() {
return this.username;
}
+ /**
+ * @return The command prefix. The prefix can change under various scenarios:
+ * 1. If the entry point has a hardcoded prefix (i.e., slash commands)
+ * 2. If there is no hardcoded prefix, we just use whatever is configured
+ */
+ public String getPrefix() {
+ if (!Strings.isEmpty(this.prefix)) {
+ return this.prefix;
+ }
+ String configuredPrefix = Config.getProperty(Config.Constants.COMMAND_PREFIX);
+ if (!Strings.isEmpty(configuredPrefix)) {
+ return configuredPrefix;
+ }
+ return "!";
+ }
+
public CommandContextConfig setUsername(String username) {
this.username = username;
return this;
}
+ public CommandContextConfig setPrefix(String prefix) {
+ this.prefix = prefix;
+ return this;
+ }
private String username;
+ private String prefix;
}
private static ThreadLocal contextConfigThreadLocal;
}
diff --git a/src/main/java/com/botdarr/commands/CommandProcessor.java b/src/main/java/com/botdarr/commands/CommandProcessor.java
index ba2031d..6738e91 100644
--- a/src/main/java/com/botdarr/commands/CommandProcessor.java
+++ b/src/main/java/com/botdarr/commands/CommandProcessor.java
@@ -1,58 +1,42 @@
package com.botdarr.commands;
-import com.botdarr.Config;
import com.botdarr.clients.ChatClientResponse;
import com.botdarr.commands.responses.CommandResponse;
import com.botdarr.commands.responses.ErrorResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.util.Strings;
import java.util.Collections;
import java.util.List;
public class CommandProcessor {
- public List processRequestMessage(List apiCommands,
- String strippedMessage,
- String username) {
+ public List processCommand(String commandPrefix,
+ List apiCommands,
+ String strippedMessage,
+ String username) {
try {
String rawMessage = strippedMessage.toLowerCase();
- String commandPrefix = getPrefix();
+ final String processedCommand;
if (rawMessage.startsWith(commandPrefix)) {
//remove the prefix character from the message
- String rawMessageWithoutPrefix = rawMessage.trim().substring(1);
- for (Command apiCommand : apiCommands) {
- String command = apiCommand.getIdentifier().toLowerCase();
- boolean foundCommand = apiCommand.hasArguments() ? rawMessageWithoutPrefix.startsWith(command) : rawMessageWithoutPrefix.equalsIgnoreCase(command);
- if (foundCommand) {
- String commandOperation = rawMessageWithoutPrefix.replaceAll(command, "");
- try {
- CommandContext
- .start()
- .setUsername(username);
- return apiCommand.execute(commandOperation.trim());
- } finally {
- CommandContext.end();
- }
- }
+ processedCommand = rawMessage.trim().substring(1);
+ } else {
+ processedCommand = rawMessage;
+ }
+ for (Command apiCommand : apiCommands) {
+ String command = apiCommand.getIdentifier().toLowerCase();
+ boolean foundCommand = apiCommand.hasArguments() ? processedCommand.startsWith(command) : processedCommand.equalsIgnoreCase(command);
+ if (foundCommand) {
+ String commandOperation = processedCommand.replaceAll(command, "");
+ return apiCommand.execute(commandOperation.trim());
}
- return Collections.singletonList(new ErrorResponse("Invalid command - type " + commandPrefix + "help for command usage"));
}
-
+ return Collections.singletonList(new ErrorResponse("Invalid command - type " + commandPrefix + "help for command usage"));
} catch (Throwable e) {
LOGGER.error("Error trying to execute command " + strippedMessage, e);
return Collections.singletonList(new ErrorResponse("Error trying to parse command " + strippedMessage + ", error=" + e.getMessage()));
}
- return null;
- }
-
- public String getPrefix() {
- String configuredPrefix = Config.getProperty(Config.Constants.COMMAND_PREFIX);
- if (!Strings.isEmpty(configuredPrefix)) {
- return configuredPrefix;
- }
- return "!";
}
private static final Logger LOGGER = LogManager.getLogger(CommandProcessor.class);
diff --git a/src/main/java/com/botdarr/commands/HelpCommands.java b/src/main/java/com/botdarr/commands/HelpCommands.java
index e8a45bc..168a89f 100644
--- a/src/main/java/com/botdarr/commands/HelpCommands.java
+++ b/src/main/java/com/botdarr/commands/HelpCommands.java
@@ -11,25 +11,25 @@ public static List getCommands(List radarrCommands,
List sonarrCommands,
List lidarrCommands) {
return new ArrayList() {{
- add(new BaseHelpCommand("help", "") {
+ add(new BaseHelpCommand("help", "Shows all the help commands") {
@Override
public List execute(String command) {
return Collections.singletonList(new HelpResponse());
}
});
- add(new BaseHelpCommand("movies help", "") {
+ add(new BaseHelpCommand("movies help", "Shows all the movie commands") {
@Override
public List execute(String command) {
return Collections.singletonList(new MoviesHelpResponse(radarrCommands));
}
});
- add(new BaseHelpCommand("shows help", "") {
+ add(new BaseHelpCommand("shows help", "Shows all the show commands") {
@Override
public List execute(String command) {
return Collections.singletonList(new ShowsHelpResponse(sonarrCommands));
}
});
- add(new BaseHelpCommand("music help", "") {
+ add(new BaseHelpCommand("music help", "Shows all the music commands") {
@Override
public List execute(String command) {
return Collections.singletonList(new MusicHelpResponse(lidarrCommands));
diff --git a/src/main/resources/version.txt b/src/main/resources/version.txt
index 229793a..1e20ec3 100644
--- a/src/main/resources/version.txt
+++ b/src/main/resources/version.txt
@@ -1 +1 @@
-5.3.5
\ No newline at end of file
+5.4.0
\ No newline at end of file
diff --git a/src/test/java/com/botdarr/ConfigTests.java b/src/test/java/com/botdarr/ConfigTests.java
index 280ff80..ce1bca3 100644
--- a/src/test/java/com/botdarr/ConfigTests.java
+++ b/src/test/java/com/botdarr/ConfigTests.java
@@ -112,6 +112,25 @@ public void getConfig_telegramGroupIdsContainNegativeOneHundred() throws Excepti
Config.getProperty("");
}
+ @Test
+ public void getPrefix_returnsDefaultPrefix() throws Exception {
+ Properties properties = new Properties();
+ properties.put("telegram-token", "%H$$54j45i");
+ properties.put("telegram-private-groups", "group1:100459349");
+ writeFakePropertiesFile(properties);
+ Assert.assertEquals("!", Config.getPrefix());
+ }
+
+ @Test
+ public void getPrefix_returnsConfiguredPrefix() throws Exception {
+ Properties properties = new Properties();
+ properties.put("telegram-token", "%H$$54j45i");
+ properties.put("telegram-private-groups", "group1:100459349");
+ properties.put("command-prefix", "$");
+ writeFakePropertiesFile(properties);
+ Assert.assertEquals("$", Config.getPrefix());
+ }
+
private void writeFakePropertiesFile(Properties properties) throws Exception {
File propertiesFile = new File(temporaryFolder.getRoot(), "properties");
Deencapsulation.setField(Config.class, "propertiesPath", propertiesFile.getPath());
diff --git a/src/test/java/com/botdarr/clients/discord/DiscordBootstrapTests.java b/src/test/java/com/botdarr/clients/discord/DiscordBootstrapTests.java
new file mode 100644
index 0000000..ae2ccf9
--- /dev/null
+++ b/src/test/java/com/botdarr/clients/discord/DiscordBootstrapTests.java
@@ -0,0 +1,156 @@
+package com.botdarr.clients.discord;
+
+import com.botdarr.Config;
+import com.botdarr.commands.Command;
+import mockit.Deencapsulation;
+import mockit.Expectations;
+import mockit.Mocked;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.interactions.commands.build.CommandData;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Properties;
+
+public class DiscordBootstrapTests {
+ @Before
+ public void beforeEachTest() {
+ writeFakePropertiesFile(getDefaultProperties());
+ }
+
+ @Test
+ public void convertCommandToCommandData_commandDescriptionGreaterThan100Characters() {
+ String longDescription = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffxd";
+ new Expectations() {{
+ mockedCommand.getDescription(); result = longDescription;
+ mockedCommand.getCommandText(); result = "command1";
+ mockedCommand.getInput(); result = Collections.emptyList();
+ }};
+ CommandData commandData = new DiscordBootstrap().convertCommandToCommandData(mockedCommand);
+ Assert.assertEquals(longDescription.substring(0, 97) + "...", commandData.getDescription());
+ }
+
+ @Test
+ public void convertCommandToCommandData_commandDescriptionLessThan100Characters() {
+ String longDescription = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
+ new Expectations() {{
+ mockedCommand.getDescription(); result = longDescription;
+ mockedCommand.getCommandText(); result = "command1";
+ mockedCommand.getInput(); result = Collections.emptyList();
+ }};
+ CommandData commandData = new DiscordBootstrap().convertCommandToCommandData(mockedCommand);
+ Assert.assertEquals(longDescription, commandData.getDescription());
+ }
+
+ @Test
+ public void convertCommandToCommandData_commandInputConvertedToSlashCommandFormat() {
+ String description = "description";
+ new Expectations() {{
+ mockedCommand.getDescription(); result = description;
+ mockedCommand.getCommandText(); result = "command input1 input2";
+ mockedCommand.getInput(); result = Collections.emptyList();
+ }};
+ CommandData commandData = new DiscordBootstrap().convertCommandToCommandData(mockedCommand);
+ Assert.assertEquals(description, commandData.getDescription());
+ Assert.assertEquals("command-input1-input2", commandData.getName());
+ }
+
+ @Test
+ public void getCommandFromEmbed_returnsNullDueMissingFieldsInEmbed() {
+ new Expectations() {{
+ mockedEmbed.getFields(); result = Collections.emptyList();
+ }};
+ String command = new DiscordBootstrap().getCommandFromEmbed(mockedEmbed);
+ Assert.assertNull(command);
+ }
+
+ @Test
+ public void getCommandFromEmbed_returnsNullDueFieldNotMatchingExpectedFieldNames() {
+ new Expectations() {{
+ mockedEmbed.getFields(); result = new ArrayList(){{
+ add(new MessageEmbed.Field("unknown-field1", "", false));
+ }};
+ }};
+ String command = new DiscordBootstrap().getCommandFromEmbed(mockedEmbed);
+ Assert.assertNull(command);
+ }
+
+ @Test
+ public void getCommandFromEmbed_returnsMovieCommand() {
+ new Expectations() {{
+ mockedEmbed.getFields(); result = new ArrayList(){{
+ add(new MessageEmbed.Field("TmdbId", "43234", false));
+ }};
+ mockedEmbed.getTitle(); result = "MovieTitle1";
+ }};
+ String command = new DiscordBootstrap().getCommandFromEmbed(mockedEmbed);
+ Assert.assertEquals("!movie id add MovieTitle1 43234", command);
+ }
+
+ @Test
+ public void getCommandFromEmbed_returnsShowCommand() {
+ new Expectations() {{
+ mockedEmbed.getFields(); result = new ArrayList(){{
+ add(new MessageEmbed.Field("TvdbId", "43234", false));
+ }};
+ mockedEmbed.getTitle(); result = "ShowTitle1";
+ }};
+ String command = new DiscordBootstrap().getCommandFromEmbed(mockedEmbed);
+ Assert.assertEquals("!show id add ShowTitle1 43234", command);
+ }
+
+ @Test
+ public void getCommandFromEmbed_returnsArtistCommand() {
+ new Expectations() {{
+ mockedEmbed.getFields(); result = new ArrayList(){{
+ add(new MessageEmbed.Field("ForeignArtistId", "43234", false));
+ }};
+ mockedEmbed.getTitle(); result = "ArtistTitle1";
+ }};
+ String command = new DiscordBootstrap().getCommandFromEmbed(mockedEmbed);
+ Assert.assertEquals("!music artist id add ArtistTitle1 43234", command);
+ }
+
+ private void writeFakePropertiesFile(Properties properties) {
+ File propertiesFile = null;
+ try {
+ propertiesFile = temporaryFolder.newFile("properties");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ Deencapsulation.setField(Config.class, "propertiesPath", propertiesFile.getPath());
+ try (FileOutputStream fos = new FileOutputStream(propertiesFile)) {
+ properties.store(fos, "");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Properties getDefaultProperties() {
+ Properties properties = new Properties();
+ properties.setProperty("discord-token", "G$K$GK");
+ properties.setProperty("discord-channels", "plex-testing2");
+ properties.setProperty("radarr-url", "http://localhost:444");
+ properties.setProperty("radarr-token", "FSJDkjmf#$Kf3");
+ properties.setProperty("radarr-path", "/movies");
+ properties.setProperty("radarr-default-profile", "any");
+ return properties;
+ }
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Mocked
+ private MessageEmbed mockedEmbed;
+
+ @Mocked
+ private Command mockedCommand;
+}
diff --git a/src/test/java/com/botdarr/commands/CommandProcessorTests.java b/src/test/java/com/botdarr/commands/CommandProcessorTests.java
index 9d6abc8..edbbacb 100644
--- a/src/test/java/com/botdarr/commands/CommandProcessorTests.java
+++ b/src/test/java/com/botdarr/commands/CommandProcessorTests.java
@@ -1,5 +1,6 @@
package com.botdarr.commands;
+import com.botdarr.Config;
import com.botdarr.TestCommandResponse;
import com.botdarr.api.lidarr.LidarrApi;
import com.botdarr.api.lidarr.LidarrCommands;
@@ -14,11 +15,16 @@
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import java.util.Properties;
/**
* These tests specifically test commands that take no arguments and commands that take arguments
@@ -27,6 +33,7 @@ public class CommandProcessorTests {
@Before
public void beforeEachTest() {
mockCommandPrefix("!");
+ writeFakePropertiesFile(getDefaultProperties());
}
@Test
@@ -334,7 +341,7 @@ private void validateInvalidCommandIdentifier(String invalidCommand) {
private List validateValidCommand(String validCommand) {
CommandProcessor commandProcessor = new CommandProcessor();
List commandResponses =
- commandProcessor.processRequestMessage(getCommandsToTest(), validCommand, "user1");
+ commandProcessor.processCommand(CommandContext.getConfig().getPrefix(), getCommandsToTest(), validCommand, "user1");
//we are just making sure no error responses are returned since they signify a failure with the command
if (commandResponses != null) {
for (CommandResponse response: commandResponses) {
@@ -348,7 +355,7 @@ private List validateValidCommand(String validCommand) {
private void validateInvalidCommand(String invalidCommand, String expectedErrorResponseString) {
CommandProcessor commandProcessor = new CommandProcessor();
List commandResponses =
- commandProcessor.processRequestMessage(getCommandsToTest(), invalidCommand, "user1");
+ commandProcessor.processCommand(CommandContext.getConfig().getPrefix(), getCommandsToTest(), invalidCommand, "user1");
if (commandResponses != null) {
Assert.assertEquals(1, commandResponses.size());
CommandResponse commandResponse = commandResponses.get(0);
@@ -380,6 +387,35 @@ private List getCommandsToTest() {
return commands;
}
+ private void writeFakePropertiesFile(Properties properties) {
+ File propertiesFile = null;
+ try {
+ propertiesFile = temporaryFolder.newFile("properties");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ Deencapsulation.setField(Config.class, "propertiesPath", propertiesFile.getPath());
+ try (FileOutputStream fos = new FileOutputStream(propertiesFile)) {
+ properties.store(fos, "");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Properties getDefaultProperties() {
+ Properties properties = new Properties();
+ properties.setProperty("discord-token", "G$K$GK");
+ properties.setProperty("discord-channels", "plex-testing2");
+ properties.setProperty("radarr-url", "http://localhost:444");
+ properties.setProperty("radarr-token", "FSJDkjmf#$Kf3");
+ properties.setProperty("radarr-path", "/movies");
+ properties.setProperty("radarr-default-profile", "any");
+ return properties;
+ }
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
@Injectable
private RadarrApi radarrApi;