From 496e3af4ea4a4a1342e45a97a33c92af4ec0ffb4 Mon Sep 17 00:00:00 2001 From: Chew Date: Wed, 5 Jun 2024 13:50:21 -0500 Subject: [PATCH] add standings command --- src/main/java/pw/chew/mlb/MLBBot.java | 10 +- .../chew/mlb/commands/StandingsCommand.java | 70 ++++++++++++++ .../java/pw/chew/mlb/util/MLBAPIUtil.java | 91 +++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/main/java/pw/chew/mlb/commands/StandingsCommand.java diff --git a/src/main/java/pw/chew/mlb/MLBBot.java b/src/main/java/pw/chew/mlb/MLBBot.java index 2e65cbc..278084b 100644 --- a/src/main/java/pw/chew/mlb/MLBBot.java +++ b/src/main/java/pw/chew/mlb/MLBBot.java @@ -18,6 +18,7 @@ import pw.chew.mlb.commands.ScoreCommand; import pw.chew.mlb.commands.SetInfoCommand; import pw.chew.mlb.commands.ShutdownCommand; +import pw.chew.mlb.commands.StandingsCommand; import pw.chew.mlb.commands.StartGameCommand; import pw.chew.mlb.commands.StopGameCommand; import pw.chew.mlb.listeners.InteractionHandler; @@ -59,8 +60,13 @@ public static void main(String[] args) throws IOException { client.useHelpBuilder(false); client.addCommands(new ShutdownCommand(), new AdminCommand()); - client.addSlashCommands(new StartGameCommand(), new StopGameCommand(), new ScoreCommand(), new SetInfoCommand(), new ConfigCommand(), - new PlanGameCommand()); + client.addSlashCommands( + // Main commands + new StartGameCommand(), new StopGameCommand(), new ScoreCommand(), new SetInfoCommand(), new ConfigCommand(), + new PlanGameCommand() + , // Util Commands + new StandingsCommand() + ); //client.forceGuildOnly("148195924567392257"); diff --git a/src/main/java/pw/chew/mlb/commands/StandingsCommand.java b/src/main/java/pw/chew/mlb/commands/StandingsCommand.java new file mode 100644 index 0000000..5d66e9e --- /dev/null +++ b/src/main/java/pw/chew/mlb/commands/StandingsCommand.java @@ -0,0 +1,70 @@ +package pw.chew.mlb.commands; + +import com.jagrosh.jdautilities.command.SlashCommand; +import com.jagrosh.jdautilities.command.SlashCommandEvent; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import pw.chew.mlb.util.MLBAPIUtil; +import pw.chew.mlb.util.TeamEmoji; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class StandingsCommand extends SlashCommand { + + public StandingsCommand() { + this.name = "standings"; + this.help = "Get the current standings."; + this.guildOnly = false; + this.options = List.of( + new OptionData(OptionType.STRING, "division", "Select a division to view standings for!", true) + // hardcode MLB for now. eventually milb will be added + .addChoice("AL East", "American League East") + .addChoice("AL Central", "American League Central") + .addChoice("AL West", "American League West") + .addChoice("NL East", "National League East") + .addChoice("NL Central", "National League Central") + .addChoice("NL West", "National League West") + ); + + // TODO: Future, make this installable in user contexts + + this.descriptionLocalization = Map.of( + DiscordLocale.ENGLISH_US, "Get the current standings.", + DiscordLocale.SPANISH, "Obtenga las posiciones actuales.", + DiscordLocale.GERMAN, "Erhalten Sie die aktuellen Platzierungen." + ); + } + + @Override + protected void execute(SlashCommandEvent event) { + String division = event.optString("division", "American League West"); + + // first we get standings + var standings = MLBAPIUtil.getStandings().get(division); + + List teams = new ArrayList<>(); + for (MLBAPIUtil.Standing standing : standings) { + teams.add( + """ + **%s) %s %s** + **%s** W | **%s** L | **%s** pct | **%s** GB | **%s** Home | **%s** Away | **%s** L10 + """.formatted( + standing.rank(), TeamEmoji.fromName(standing.teamName()).getAsMention(), standing.teamName(), + standing.wins(), standing.losses(), standing.winPct(), + standing.gamesBack(), standing.homeRecord(), standing.awayRecord(), standing.lastTen() + ) + ); + } + + // make a cute lil embed + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Standings for " + division) + .setDescription(String.join("\n", teams)); + + event.replyEmbeds(embed.build()).setEphemeral(true).queue(); + } +} diff --git a/src/main/java/pw/chew/mlb/util/MLBAPIUtil.java b/src/main/java/pw/chew/mlb/util/MLBAPIUtil.java index aa027ec..c9bb515 100644 --- a/src/main/java/pw/chew/mlb/util/MLBAPIUtil.java +++ b/src/main/java/pw/chew/mlb/util/MLBAPIUtil.java @@ -75,6 +75,34 @@ public static List getLineup(String gamePk, String homeAway) { return lineupPlayers; } + /** + * Gets the current MLB standings. + * + * TODO: Support MiLB. + */ + public static Map> getStandings() { + JSONArray standings = new JSONObject(RestClient.get("https://statsapi.mlb.com/api/v1/standings?leagueId=103,104&hydrate=division&season=%s".formatted(SEASON))).getJSONArray("records"); + HashMap> standingsMap = new HashMap<>(); + for (int i = 0; i < standings.length(); i++) { + JSONObject division = standings.getJSONObject(i); + // division > name + String divisionName = division.getJSONObject("division").getString("name"); + + // division records + JSONArray teamRecords = division.getJSONArray("teamRecords"); + + // convert each teamRecord object to a Standing object + List divisionStandings = new ArrayList<>(); + for (int j = 0; j < teamRecords.length(); j++) { + divisionStandings.add(new Standing(teamRecords.getJSONObject(j))); + } + + standingsMap.put(divisionName, divisionStandings); + } + return standingsMap; + + } + public record Sports(JSONArray raw) { public List asChoices() { List choices = new ArrayList<>(); @@ -177,4 +205,67 @@ public String abbreviation() { return raw.getString("abbreviation"); } } + + public record Standing(JSONObject raw) { + public String teamName() { + // team > name + return raw.getJSONObject("team").getString("name"); + } + + public String streak() { + // streak > streakCode + return raw.getJSONObject("streak").getString("streakCode"); + } + + public String rank() { + // divisionRank + return raw.getString("divisionRank"); + } + + public int wins() { + // wins + return raw.getInt("wins"); + } + + public int losses() { + // losses + return raw.getInt("losses"); + } + + public String winPct() { + // winningPercentage + return raw.getString("winningPercentage"); + } + + public int runDifferential() { + // runDifferential + return raw.getInt("runDifferential"); + } + + public String gamesBack() { + // gamesBack + return raw.getString("gamesBack"); + } + + public String homeRecord() { + // records > splitRecords[0] *jsonobject* + JSONObject home = raw.getJSONObject("records").getJSONArray("splitRecords").getJSONObject(0); + // wins - losses + return "%s-%s".formatted(home.getInt("wins"), home.getInt("losses")); + } + + public String awayRecord() { + // records > splitRecords[1] *jsonobject* + JSONObject away = raw.getJSONObject("records").getJSONArray("splitRecords").getJSONObject(1); + // wins - losses + return "%s-%s".formatted(away.getInt("wins"), away.getInt("losses")); + } + + public String lastTen() { + // records > splitRecords[8] *jsonobject* + JSONObject lastTen = raw.getJSONObject("records").getJSONArray("splitRecords").getJSONObject(8); + // wins - losses + return "%s-%s".formatted(lastTen.getInt("wins"), lastTen.getInt("losses")); + } + } }