From 28c0f1d750f4e9098d7256ac72fcc32ff35897cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beatrice=20Dellac=C3=A0?= Date: Mon, 19 Dec 2022 21:42:55 +0100 Subject: [PATCH] Implement urban dictionary lookup command --- pom.xml | 11 ++ .../wtf/beatrice/hidekobot/HidekoBot.java | 1 + .../message/UrbanDictionaryCommand.java | 128 ++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 src/main/java/wtf/beatrice/hidekobot/commands/message/UrbanDictionaryCommand.java diff --git a/pom.xml b/pom.xml index de9b1bf..b1f95f4 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,17 @@ snakeyaml 1.33 + + org.jsoup + jsoup + 1.15.3 + + + org.apache.commons + commons-text + 1.10.0 + + diff --git a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java index 96a477e..dbf2bc1 100644 --- a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java +++ b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java @@ -139,6 +139,7 @@ public class HidekoBot messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.LoveCalculatorCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.MagicBallCommand()); messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.SayCommand()); + messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.UrbanDictionaryCommand()); Cache.setMessageCommandListener(messageCommandListener); // register listeners diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/UrbanDictionaryCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/UrbanDictionaryCommand.java new file mode 100644 index 0000000..947feb0 --- /dev/null +++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/UrbanDictionaryCommand.java @@ -0,0 +1,128 @@ +package wtf.beatrice.hidekobot.commands.message; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.apache.commons.text.WordUtils; +import org.jetbrains.annotations.Nullable; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import wtf.beatrice.hidekobot.Cache; +import wtf.beatrice.hidekobot.objects.commands.MessageCommand; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public class UrbanDictionaryCommand implements MessageCommand +{ + + @Override + public LinkedList getCommandLabels() { + return new LinkedList<>(Arrays.asList("urban", "urbandictionary", "ud")); + } + + @Nullable + @Override + public List getPermissions() { + return null; //anyone can use it + } + + @Override + public boolean passRawArgs() { + return false; + } + + @Override + public void runCommand(MessageReceivedEvent event, String label, String[] args) + { + if(args.length == 0) + { + event.getMessage().reply("\uD83D\uDE22 I need to know what to search for!").queue(); + return; + } + + + // sanitize args by only keeping letters and numbers, and adding "+" instead of spaces for HTML parsing + StringBuilder termBuilder = new StringBuilder(); + for(int pos = 0; pos < args.length; pos++) + { + String arg = args[pos]; + + arg = arg.replaceAll("[^\\d\\w]", ""); + termBuilder.append(arg); + + if(pos + 1 != args.length) + termBuilder.append("+"); // add everywhere except on last iteration + } + + String term = termBuilder.toString(); + + // cut it to length to avoid abuse + if (term.length() > 64) term = term.substring(0, 64); + + String url = "https://www.urbandictionary.com/define.php?term=" + term; + + Document doc = null; + + try { + doc = Jsoup.connect(url).get(); + } catch (IOException e) { + event.getMessage().reply("\uD83D\uDE22 I couldn't find that term!").queue(); + return; + } + + List htmlMeanings = new ArrayList<>(); + List htmlExamples = new ArrayList<>(); + + Elements definitions = doc.getElementsByClass("definition"); + for(Element element : definitions) + { + Elements meanings = element.getElementsByClass("meaning"); + for(Element meaning : meanings) + { + htmlMeanings.add(meaning.html()); + break;// just one meaning per definition + } + + Elements examples = element.getElementsByClass("example"); + for(Element example : examples) + { + htmlExamples.add(example.html()); + break; // just one example per definition + } + } + + List plaintextMeanings = new ArrayList<>(); + List plaintextExamples = new ArrayList<>(); + + for(String htmlMeaning : htmlMeanings) + { + String text = htmlMeaning.replaceAll("<.*?>", ""); + plaintextMeanings.add(text); + } + + for(String htmlExample : htmlExamples) + { + String text = htmlExample.replaceAll("<.*?>", ""); + plaintextExamples.add(text); + } + + // make it nice to look at, compared to the html value + term = term.replaceAll("\\+", " "); + term = WordUtils.capitalizeFully(term); + + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Cache.getBotColor()); + embedBuilder.setTitle("Urban Dictionary: " + term); + embedBuilder.setAuthor(event.getAuthor().getAsTag(), null, event.getAuthor().getAvatarUrl()); + embedBuilder.addField("Definition", plaintextMeanings.get(0), false); + embedBuilder.addField("Example", plaintextExamples.get(0), false); + + event.getChannel().sendMessageEmbeds(embedBuilder.build()).queue(); + } +}