feat: fun/space commands + meme subreddit arg
- !catfact/!dogfact (feature/animals/command/AnimalFactCommand)
- !joke (jokeapi.dev), !chuck (chucknorris.io), !inspire (zenquotes.io) — feature/fun
- !apod (nasa DEMO_KEY), !iss (wheretheiss.at), !space (open-notify.org), !xkcd — feature/space
- !meme [subreddit] — optional meme-api.com/gimme/{subreddit}, 404 -> not found
This commit is contained in:
parent
b3470a0f3d
commit
bf14e03b21
15 changed files with 871 additions and 5 deletions
|
|
@ -19,6 +19,7 @@ import creator.loki.feature.config.ConfigModule;
|
||||||
import creator.loki.feature.counter.CounterModule;
|
import creator.loki.feature.counter.CounterModule;
|
||||||
import creator.loki.feature.economy.EconomyModule;
|
import creator.loki.feature.economy.EconomyModule;
|
||||||
import creator.loki.feature.entertainment.EntertainmentModule;
|
import creator.loki.feature.entertainment.EntertainmentModule;
|
||||||
|
import creator.loki.feature.fun.FunModule;
|
||||||
import creator.loki.feature.image.ImageModule;
|
import creator.loki.feature.image.ImageModule;
|
||||||
import creator.loki.feature.level.LevelModule;
|
import creator.loki.feature.level.LevelModule;
|
||||||
import creator.loki.feature.metrics.HealthHttpServer;
|
import creator.loki.feature.metrics.HealthHttpServer;
|
||||||
|
|
@ -30,6 +31,7 @@ import creator.loki.feature.profile.ProfileModule;
|
||||||
import creator.loki.feature.radio.RadioModule;
|
import creator.loki.feature.radio.RadioModule;
|
||||||
import creator.loki.feature.reactroles.ReactionRolesModule;
|
import creator.loki.feature.reactroles.ReactionRolesModule;
|
||||||
import creator.loki.feature.role.RoleModule;
|
import creator.loki.feature.role.RoleModule;
|
||||||
|
import creator.loki.feature.space.SpaceModule;
|
||||||
import creator.loki.feature.ticket.TicketModule;
|
import creator.loki.feature.ticket.TicketModule;
|
||||||
import creator.loki.feature.tiktok.TikTokModule;
|
import creator.loki.feature.tiktok.TikTokModule;
|
||||||
import creator.loki.feature.utility.UtilityModule;
|
import creator.loki.feature.utility.UtilityModule;
|
||||||
|
|
@ -67,6 +69,8 @@ public class BotModule extends AbstractModule {
|
||||||
install(new TikTokModule());
|
install(new TikTokModule());
|
||||||
install(new EntertainmentModule());
|
install(new EntertainmentModule());
|
||||||
install(new AnimalModule());
|
install(new AnimalModule());
|
||||||
|
install(new FunModule());
|
||||||
|
install(new SpaceModule());
|
||||||
install(new TicketModule());
|
install(new TicketModule());
|
||||||
install(new UtilityModule());
|
install(new UtilityModule());
|
||||||
install(new ReactionRolesModule());
|
install(new ReactionRolesModule());
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package creator.loki.feature.animals;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import creator.loki.core.registry.CommandRegistrar;
|
import creator.loki.core.registry.CommandRegistrar;
|
||||||
import creator.loki.core.registry.CommandRegistry;
|
import creator.loki.core.registry.CommandRegistry;
|
||||||
|
import creator.loki.feature.animals.command.AnimalFactCommand;
|
||||||
import creator.loki.feature.animals.command.AnimalImageCommand;
|
import creator.loki.feature.animals.command.AnimalImageCommand;
|
||||||
import creator.loki.feature.animals.command.ZooPersonCommand;
|
import creator.loki.feature.animals.command.ZooPersonCommand;
|
||||||
import creator.loki.feature.entertainment.service.RatingService;
|
import creator.loki.feature.entertainment.service.RatingService;
|
||||||
|
|
@ -25,5 +26,8 @@ public class AnimalCommandRegistrar implements CommandRegistrar {
|
||||||
for (AnimalImageCommand.Flavor flavor : AnimalImageCommand.Flavor.values()) {
|
for (AnimalImageCommand.Flavor flavor : AnimalImageCommand.Flavor.values()) {
|
||||||
registry.register(new AnimalImageCommand(flavor, animalApi));
|
registry.register(new AnimalImageCommand(flavor, animalApi));
|
||||||
}
|
}
|
||||||
|
for (AnimalFactCommand.Flavor flavor : AnimalFactCommand.Flavor.values()) {
|
||||||
|
registry.register(new AnimalFactCommand(flavor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
package creator.loki.feature.animals.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import creator.loki.embed.EmbedTemplates;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class AnimalFactCommand implements Command {
|
||||||
|
|
||||||
|
public enum Flavor {
|
||||||
|
CAT("catfact", "Случайный факт о коте", "🐱", "https://catfact.ninja/fact"),
|
||||||
|
DOG("dogfact", "Случайный факт о собаке", "🐶", "https://dog-api.kinduff.com/api/facts");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final String description;
|
||||||
|
private final String emoji;
|
||||||
|
private final String apiUrl;
|
||||||
|
|
||||||
|
Flavor(final String name, final String description, final String emoji, final String apiUrl) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.emoji = emoji;
|
||||||
|
this.apiUrl = apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmoji() {
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiUrl() {
|
||||||
|
return apiUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Color EMBED_COLOR = new Color(88, 101, 242);
|
||||||
|
|
||||||
|
private final Flavor flavor;
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public AnimalFactCommand(final Flavor flavor) {
|
||||||
|
this.flavor = flavor;
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return flavor.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return flavor.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsage() {
|
||||||
|
return flavor.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.ANIMALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🔍 Ищу факт...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
String fact = fetchFact();
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle(flavor.getEmoji() + " Факт")
|
||||||
|
.withDescription(fact)
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedTemplates.error("Ошибка", "Не удалось получить факт, попробуй позже."))
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fetchFact() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(flavor.getApiUrl()).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("API вернул " + response.code());
|
||||||
|
}
|
||||||
|
JsonObject json = JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
if (flavor == Flavor.CAT) {
|
||||||
|
return json.get("fact").getAsString();
|
||||||
|
}
|
||||||
|
JsonArray facts = json.getAsJsonArray("facts");
|
||||||
|
if (facts == null || facts.isEmpty()) {
|
||||||
|
throw new IOException("API вернул пустой список фактов");
|
||||||
|
}
|
||||||
|
return facts.get(0).getAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,7 +39,7 @@ public class MemeCommand implements Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUsage() {
|
public String getUsage() {
|
||||||
return "meme";
|
return "meme [субреддит]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -55,7 +55,8 @@ public class MemeCommand implements Command {
|
||||||
.queue(
|
.queue(
|
||||||
loadingMsg -> {
|
loadingMsg -> {
|
||||||
try {
|
try {
|
||||||
JsonObject json = fetchMeme();
|
String sub = context.getArgs().isEmpty() ? null : context.getArgs().get(0);
|
||||||
|
JsonObject json = fetchMeme(sub);
|
||||||
String memeUrl = json.get("url").getAsString();
|
String memeUrl = json.get("url").getAsString();
|
||||||
String title = json.get("title").getAsString();
|
String title = json.get("title").getAsString();
|
||||||
String subreddit = json.get("subreddit").getAsString();
|
String subreddit = json.get("subreddit").getAsString();
|
||||||
|
|
@ -76,11 +77,13 @@ public class MemeCommand implements Command {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject fetchMeme() throws IOException {
|
private JsonObject fetchMeme(final String subreddit) throws IOException {
|
||||||
Request request = new Request.Builder().url(MEME_API).get().build();
|
String url = subreddit == null ? MEME_API : MEME_API + "/" + subreddit;
|
||||||
|
Request request = new Request.Builder().url(url).get().build();
|
||||||
try (Response response = client.newCall(request).execute()) {
|
try (Response response = client.newCall(request).execute()) {
|
||||||
if (!response.isSuccessful() || response.body() == null) {
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
throw new IOException("meme-api вернул " + response.code());
|
throw new IOException(
|
||||||
|
subreddit == null ? "meme-api вернул " + response.code() : "сабреддит не найден");
|
||||||
}
|
}
|
||||||
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package creator.loki.feature.fun;
|
||||||
|
|
||||||
|
import creator.loki.core.registry.CommandRegistrar;
|
||||||
|
import creator.loki.core.registry.CommandRegistry;
|
||||||
|
import creator.loki.feature.fun.command.ChuckCommand;
|
||||||
|
import creator.loki.feature.fun.command.InspireCommand;
|
||||||
|
import creator.loki.feature.fun.command.JokeCommand;
|
||||||
|
|
||||||
|
public class FunCommandRegistrar implements CommandRegistrar {
|
||||||
|
@Override
|
||||||
|
public void register(final CommandRegistry registry) {
|
||||||
|
registry.register(new JokeCommand());
|
||||||
|
registry.register(new ChuckCommand());
|
||||||
|
registry.register(new InspireCommand());
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main/java/creator/loki/feature/fun/FunModule.java
Normal file
14
src/main/java/creator/loki/feature/fun/FunModule.java
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package creator.loki.feature.fun;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.multibindings.Multibinder;
|
||||||
|
import creator.loki.core.registry.CommandRegistrar;
|
||||||
|
|
||||||
|
public class FunModule extends AbstractModule {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
Multibinder.newSetBinder(binder(), CommandRegistrar.class)
|
||||||
|
.addBinding()
|
||||||
|
.to(FunCommandRegistrar.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package creator.loki.feature.fun.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import creator.loki.embed.EmbedTemplates;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class ChuckCommand implements Command {
|
||||||
|
private static final String CHUCK_API = "https://api.chucknorris.io/jokes/random";
|
||||||
|
private static final Color EMBED_COLOR = new Color(189, 8, 28);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public ChuckCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "chuck";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Случайная шутка про Чака Норриса";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.ENTERTAINMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🔍 Ищу шутку про Чака Норриса...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchJoke();
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("🥋 Чак Норрис")
|
||||||
|
.withDescription(json.get("value").getAsString())
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withThumbnail("https://api.chucknorris.io/img/avatar/chuck-norris.png")
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedTemplates.error(
|
||||||
|
"Ошибка", "Не удалось загрузить шутку, попробуй позже."))
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchJoke() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(CHUCK_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("Chuck Norris API вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
package creator.loki.feature.fun.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import creator.loki.embed.EmbedTemplates;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class InspireCommand implements Command {
|
||||||
|
private static final String INSPIRE_API = "https://zenquotes.io/api/random";
|
||||||
|
private static final Color EMBED_COLOR = new Color(39, 174, 96);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public InspireCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "inspire";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Случайная вдохновляющая цитата";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.ENTERTAINMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🔍 Ищу цитату...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject quote = fetchQuote();
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("✨ Цитата")
|
||||||
|
.withDescription("«" + quote.get("q").getAsString() + "»")
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withFooter("— " + quote.get("a").getAsString())
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedTemplates.error(
|
||||||
|
"Ошибка", "Не удалось загрузить цитату, попробуй позже."))
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchQuote() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(INSPIRE_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("ZenQuotes вернул " + response.code());
|
||||||
|
}
|
||||||
|
JsonArray array = JsonParser.parseString(response.body().string()).getAsJsonArray();
|
||||||
|
if (array.isEmpty()) {
|
||||||
|
throw new IOException("ZenQuotes вернул пустой список");
|
||||||
|
}
|
||||||
|
return array.get(0).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
package creator.loki.feature.fun.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import creator.loki.embed.EmbedTemplates;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class JokeCommand implements Command {
|
||||||
|
private static final String JOKE_API = "https://v2.jokeapi.dev/joke/Any";
|
||||||
|
private static final Color EMBED_COLOR = new Color(255, 193, 7);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public JokeCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "joke";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Случайная шутка";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.ENTERTAINMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🔍 Ищу шутку...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchJoke();
|
||||||
|
String text =
|
||||||
|
json.get("type").getAsString().equals("twopart")
|
||||||
|
? json.get("setup").getAsString()
|
||||||
|
+ "\n\n"
|
||||||
|
+ json.get("delivery").getAsString()
|
||||||
|
: json.get("joke").getAsString();
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("🤣 Шутка")
|
||||||
|
.withDescription(text)
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withFooter("Категория: " + json.get("category").getAsString())
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedTemplates.error(
|
||||||
|
"Ошибка", "Не удалось загрузить шутку, попробуй позже."))
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchJoke() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(JOKE_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("JokeAPI вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package creator.loki.feature.space;
|
||||||
|
|
||||||
|
import creator.loki.core.registry.CommandRegistrar;
|
||||||
|
import creator.loki.core.registry.CommandRegistry;
|
||||||
|
import creator.loki.feature.space.command.ApodCommand;
|
||||||
|
import creator.loki.feature.space.command.IssCommand;
|
||||||
|
import creator.loki.feature.space.command.SpaceCommand;
|
||||||
|
import creator.loki.feature.space.command.XkcdCommand;
|
||||||
|
|
||||||
|
public class SpaceCommandRegistrar implements CommandRegistrar {
|
||||||
|
@Override
|
||||||
|
public void register(final CommandRegistry registry) {
|
||||||
|
registry.register(new ApodCommand());
|
||||||
|
registry.register(new IssCommand());
|
||||||
|
registry.register(new SpaceCommand());
|
||||||
|
registry.register(new XkcdCommand());
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main/java/creator/loki/feature/space/SpaceModule.java
Normal file
14
src/main/java/creator/loki/feature/space/SpaceModule.java
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package creator.loki.feature.space;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.multibindings.Multibinder;
|
||||||
|
import creator.loki.core.registry.CommandRegistrar;
|
||||||
|
|
||||||
|
public class SpaceModule extends AbstractModule {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
Multibinder.newSetBinder(binder(), CommandRegistrar.class)
|
||||||
|
.addBinding()
|
||||||
|
.to(SpaceCommandRegistrar.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package creator.loki.feature.space.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class ApodCommand implements Command {
|
||||||
|
private static final String APOD_API = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY";
|
||||||
|
private static final int DESCRIPTION_LIMIT = 200;
|
||||||
|
private static final Color EMBED_COLOR = new Color(25, 25, 112);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public ApodCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "apod";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Астрономическая картинка дня (NASA APOD)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.INFORMATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🔍 Загружаю астрономическую картинку дня...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchApod();
|
||||||
|
String title = json.get("title").getAsString();
|
||||||
|
String image =
|
||||||
|
json.has("hdurl")
|
||||||
|
? json.get("hdurl").getAsString()
|
||||||
|
: json.get("url").getAsString();
|
||||||
|
String explanation = truncate(json.get("explanation").getAsString());
|
||||||
|
String date = json.get("date").getAsString();
|
||||||
|
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("🌌 " + title)
|
||||||
|
.withImage(image)
|
||||||
|
.withDescription(explanation)
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withFooter("NASA APOD · " + date)
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessage("❌ Не удалось загрузить картинку дня: " + e.getMessage())
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchApod() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(APOD_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("NASA APOD вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String truncate(final String text) {
|
||||||
|
if (text.length() <= DESCRIPTION_LIMIT) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text.substring(0, DESCRIPTION_LIMIT).trim() + "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
107
src/main/java/creator/loki/feature/space/command/IssCommand.java
Normal file
107
src/main/java/creator/loki/feature/space/command/IssCommand.java
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
package creator.loki.feature.space.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class IssCommand implements Command {
|
||||||
|
private static final String ISS_API = "https://api.wheretheiss.at/v1/satellites/25544";
|
||||||
|
private static final Color EMBED_COLOR = new Color(52, 152, 219);
|
||||||
|
private static final DateTimeFormatter TIME_FORMAT =
|
||||||
|
DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss").withLocale(Locale.ROOT);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public IssCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "iss";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Текущее положение МКС на орбите";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.INFORMATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🛰️ Получаю данные о МКС...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchIss();
|
||||||
|
String latitude = formatCoordinate(json.get("latitude").getAsDouble(), "N", "S");
|
||||||
|
String longitude = formatCoordinate(json.get("longitude").getAsDouble(), "E", "W");
|
||||||
|
String altitude =
|
||||||
|
String.format(Locale.ROOT, "%.0f км", json.get("altitude").getAsDouble());
|
||||||
|
String velocity =
|
||||||
|
String.format(Locale.ROOT, "%.0f км/ч", json.get("velocity").getAsDouble());
|
||||||
|
String time =
|
||||||
|
TIME_FORMAT.format(
|
||||||
|
Instant.ofEpochSecond(json.get("timestamp").getAsLong())
|
||||||
|
.atZone(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("🛰️ Международная космическая станция")
|
||||||
|
.addField("Широта", latitude, true)
|
||||||
|
.addField("Долгота", longitude, true)
|
||||||
|
.addField("Высота", altitude, true)
|
||||||
|
.addField("Скорость", velocity, true)
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withFooter("Время (UTC): " + time)
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg
|
||||||
|
.editMessage("❌ Не удалось получить данные о МКС: " + e.getMessage())
|
||||||
|
.queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchIss() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(ISS_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("Where The ISS At вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatCoordinate(
|
||||||
|
final double value, final String positive, final String negative) {
|
||||||
|
char sign = value >= 0 ? positive.charAt(0) : negative.charAt(0);
|
||||||
|
return String.format(Locale.ROOT, "%.4f° %s", Math.abs(value), sign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package creator.loki.feature.space.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class SpaceCommand implements Command {
|
||||||
|
private static final String ASTROS_API = "http://api.open-notify.org/astros.json";
|
||||||
|
private static final int MAX_NAMES = 40;
|
||||||
|
private static final int FIELD_SIZE = 10;
|
||||||
|
private static final Color EMBED_COLOR = new Color(70, 70, 130);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public SpaceCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "space";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Кто сейчас находится в космосе";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.INFORMATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🚀 Узнаю, кто сейчас в космосе...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchAstros();
|
||||||
|
int number = json.get("number").getAsInt();
|
||||||
|
JsonArray people = json.getAsJsonArray("people");
|
||||||
|
|
||||||
|
EmbedFactory embed =
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("🚀 Люди в космосе")
|
||||||
|
.withDescription("Сейчас на орбите: " + number)
|
||||||
|
.withColor(EMBED_COLOR);
|
||||||
|
|
||||||
|
int shown = Math.min(people.size(), MAX_NAMES);
|
||||||
|
for (int start = 0; start < shown; start += FIELD_SIZE) {
|
||||||
|
int end = Math.min(start + FIELD_SIZE, shown);
|
||||||
|
StringBuilder fieldValue = new StringBuilder();
|
||||||
|
for (int i = start; i < end; i++) {
|
||||||
|
JsonObject person = people.get(i).getAsJsonObject();
|
||||||
|
fieldValue
|
||||||
|
.append(person.get("name").getAsString())
|
||||||
|
.append(" (")
|
||||||
|
.append(person.get("craft").getAsString())
|
||||||
|
.append(")\n");
|
||||||
|
}
|
||||||
|
embed.addField(
|
||||||
|
"Экипаж " + (start / FIELD_SIZE + 1), fieldValue.toString(), false);
|
||||||
|
}
|
||||||
|
if (people.size() > shown) {
|
||||||
|
embed.addField(
|
||||||
|
"…", "И ещё " + (people.size() - shown) + " человек на орбите", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingMsg.editMessageEmbeds(embed.build()).queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg.editMessage("❌ Не удалось получить данные: " + e.getMessage()).queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchAstros() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(ASTROS_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("Open Notify вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
package creator.loki.feature.space.command;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import creator.loki.command.Command;
|
||||||
|
import creator.loki.command.CommandCategories;
|
||||||
|
import creator.loki.command.CommandContext;
|
||||||
|
import creator.loki.embed.EmbedFactory;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class XkcdCommand implements Command {
|
||||||
|
private static final String XKCD_API = "https://xkcd.com/info.0.json";
|
||||||
|
private static final Color EMBED_COLOR = new Color(150, 150, 150);
|
||||||
|
|
||||||
|
private final OkHttpClient client;
|
||||||
|
|
||||||
|
public XkcdCommand() {
|
||||||
|
this.client =
|
||||||
|
new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(6, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(8, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "xkcd";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Последний комикс xkcd";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCategory() {
|
||||||
|
return CommandCategories.INFORMATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(final CommandContext context) {
|
||||||
|
context
|
||||||
|
.getChannel()
|
||||||
|
.sendMessage("🧐 Загружаю свежий xkcd...")
|
||||||
|
.queue(
|
||||||
|
loadingMsg -> {
|
||||||
|
try {
|
||||||
|
JsonObject json = fetchXkcd();
|
||||||
|
int num = json.get("num").getAsInt();
|
||||||
|
String title = json.get("title").getAsString();
|
||||||
|
String image = json.get("img").getAsString();
|
||||||
|
String alt = json.get("alt").getAsString();
|
||||||
|
String date =
|
||||||
|
json.get("day").getAsString()
|
||||||
|
+ "."
|
||||||
|
+ json.get("month").getAsString()
|
||||||
|
+ "."
|
||||||
|
+ json.get("year").getAsString();
|
||||||
|
|
||||||
|
loadingMsg
|
||||||
|
.editMessageEmbeds(
|
||||||
|
EmbedFactory.create()
|
||||||
|
.withTitle("📐 " + title)
|
||||||
|
.withImage(image)
|
||||||
|
.withDescription(alt)
|
||||||
|
.withColor(EMBED_COLOR)
|
||||||
|
.withFooter("#" + num + " · " + date)
|
||||||
|
.build())
|
||||||
|
.queue();
|
||||||
|
} catch (IOException | IllegalStateException e) {
|
||||||
|
loadingMsg.editMessage("❌ Не удалось загрузить xkcd: " + e.getMessage()).queue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonObject fetchXkcd() throws IOException {
|
||||||
|
Request request = new Request.Builder().url(XKCD_API).get().build();
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful() || response.body() == null) {
|
||||||
|
throw new IOException("xkcd вернул " + response.code());
|
||||||
|
}
|
||||||
|
return JsonParser.parseString(response.body().string()).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue