From 78a7da442b261241f36828d5f0321bfc49f4ed45 Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Wed, 24 Jan 2024 01:20:19 -0800 Subject: [PATCH] Initial refactor to organize button interactions --- .../main/java/musicbot/ButtonInteraction.java | 9 ++ .../musicbot/ButtonInteractionManager.java | 29 +++++++ app/src/main/java/musicbot/Listeners.java | 53 ++++++++++++ app/src/main/java/musicbot/Main.java | 22 +++-- .../java/musicbot/RecommendationService.java | 38 ++++++++ .../MoreRecommendation.java | 86 +++++++++++++++++++ 6 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/musicbot/ButtonInteraction.java create mode 100644 app/src/main/java/musicbot/ButtonInteractionManager.java create mode 100644 app/src/main/java/musicbot/Listeners.java create mode 100644 app/src/main/java/musicbot/RecommendationService.java create mode 100644 app/src/main/java/musicbot/buttonInteractions/MoreRecommendation.java diff --git a/app/src/main/java/musicbot/ButtonInteraction.java b/app/src/main/java/musicbot/ButtonInteraction.java new file mode 100644 index 0000000..6f35809 --- /dev/null +++ b/app/src/main/java/musicbot/ButtonInteraction.java @@ -0,0 +1,9 @@ +package musicbot; + +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; + +public interface ButtonInteraction { + String getName(); + + void execute(ButtonInteractionEvent event); +} diff --git a/app/src/main/java/musicbot/ButtonInteractionManager.java b/app/src/main/java/musicbot/ButtonInteractionManager.java new file mode 100644 index 0000000..1afca97 --- /dev/null +++ b/app/src/main/java/musicbot/ButtonInteractionManager.java @@ -0,0 +1,29 @@ +package musicbot; + +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class ButtonInteractionManager extends ListenerAdapter { + private final List buttonInteractions = new ArrayList<>(); + + @Override + public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { + final String id = event.getComponent().getId(); + + final String[] args = id.split("_"); + + for (final ButtonInteraction buttonInteraction : buttonInteractions) { + if (args[0].equals(buttonInteraction.getName())) { + buttonInteraction.execute(event); + } + } + } + + public void add(@NotNull final ButtonInteraction buttonInteraction) { + buttonInteractions.add(buttonInteraction); + } +} diff --git a/app/src/main/java/musicbot/Listeners.java b/app/src/main/java/musicbot/Listeners.java new file mode 100644 index 0000000..4245de7 --- /dev/null +++ b/app/src/main/java/musicbot/Listeners.java @@ -0,0 +1,53 @@ +package musicbot; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import org.jetbrains.annotations.NotNull; +import java.util.List; + +public class Listeners extends ListenerAdapter { + + @Override + public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { + final String id = event.getComponent().getId(); + final String label = event.getComponent().getLabel(); + + final String[] args = id.split("_"); + event.deferReply().queue(); + + if (args[0].equalsIgnoreCase("recommend")) { + + final YoutubeSearch youtubeSearch = new YoutubeSearch(); + final String result = youtubeSearch.searchForMusic(label, args[1]); + + event.getHook().sendMessage(result).queue(); + } + + if (args[0].equalsIgnoreCase("genre")) { + final int page = Integer.parseInt(args[1]); + final int offset = page * 10; + final int index = offset + 10; + final int nextPage = page + 1; + + final SpotifyClient spotifyClient = new SpotifyClient(); + final List genres = spotifyClient.findGenres(); + final int maxSize = genres.size(); + final int maxPage = (int) Math.floor(maxSize / 10); + + final EmbedBuilder eb = new EmbedBuilder(); + + if (nextPage <= maxPage) { + genres.subList(offset, index).forEach(genreItem -> eb.addField(genreItem, "", false)); + + event.getHook().sendMessageEmbeds(eb.build()).addActionRow( + Button.primary("genre_" + nextPage, "More") + ).queue(); + } else { + genres.subList(offset, maxSize).forEach(genreItem -> eb.addField(genreItem, "", false)); + event.getHook().sendMessageEmbeds(eb.build()).queue(); + } + } + } +} diff --git a/app/src/main/java/musicbot/Main.java b/app/src/main/java/musicbot/Main.java index 74beeec..1f056e6 100644 --- a/app/src/main/java/musicbot/Main.java +++ b/app/src/main/java/musicbot/Main.java @@ -1,5 +1,6 @@ package musicbot; +import musicbot.buttonInteractions.MoreRecommendation; import musicbot.commands.Artist; import musicbot.commands.Genres; import musicbot.commands.MusicVideo; @@ -11,12 +12,21 @@ public class Main { final JDA jda = JDABuilder .createDefault(Token.TOKEN) .build(); - final CommandManager manager = new CommandManager(); - manager.add(new Artist()); - manager.add(new Genres()); - manager.add(new MusicVideo()); - manager.add(new Recommend()); - jda.addEventListener(manager); + final CommandManager commandManager = new CommandManager(); + final ButtonInteractionManager buttonInteractionManager = new ButtonInteractionManager(); + + // commands + commandManager.add(new Artist()); + commandManager.add(new Genres()); + commandManager.add(new MusicVideo()); + commandManager.add(new Recommend()); + + // button interactions + buttonInteractionManager.add(new MoreRecommendation()); + + // add the managers + jda.addEventListener(commandManager); + jda.addEventListener(buttonInteractionManager); jda.addEventListener(new Listeners()); } } diff --git a/app/src/main/java/musicbot/RecommendationService.java b/app/src/main/java/musicbot/RecommendationService.java new file mode 100644 index 0000000..2f74b8b --- /dev/null +++ b/app/src/main/java/musicbot/RecommendationService.java @@ -0,0 +1,38 @@ +package musicbot; + +import com.google.common.collect.ImmutableList; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import se.michaelthelin.spotify.model_objects.specification.Artist; +import se.michaelthelin.spotify.model_objects.specification.ArtistSimplified; +import se.michaelthelin.spotify.model_objects.specification.Track; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class RecommendationService { + + public List getRecommendations(final String artist, final String genre, final int page) { + + if (artist.isEmpty() && genre.isEmpty()) { + return ImmutableList.of(); + } + final SpotifyClient spotifyClient = new SpotifyClient(); + final Optional maybeArtistId = findArtistId(artist); + final String artistId = maybeArtistId.orElse(""); + final List tracks = spotifyClient.findRecommendations(artistId, genre); + + return tracks; + } + + private Optional findArtistId(final String artist) { + final SpotifyClient spotifyClient = new SpotifyClient(); + final Optional maybeArtist = spotifyClient.findArtist(artist); + + return maybeArtist.map(Artist::getId); + } +} diff --git a/app/src/main/java/musicbot/buttonInteractions/MoreRecommendation.java b/app/src/main/java/musicbot/buttonInteractions/MoreRecommendation.java new file mode 100644 index 0000000..21225d7 --- /dev/null +++ b/app/src/main/java/musicbot/buttonInteractions/MoreRecommendation.java @@ -0,0 +1,86 @@ +package musicbot.buttonInteractions; + +import musicbot.ButtonInteraction; +import musicbot.RecommendationService; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import se.michaelthelin.spotify.model_objects.specification.ArtistSimplified; +import se.michaelthelin.spotify.model_objects.specification.Track; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class MoreRecommendation implements ButtonInteraction { + private static final int INCREMENT = 5; + private static final String ARGS_DELIMITER = "_"; + private static final String ARTIST_GENRE_DELIMITER = "--"; + private static final int NUM_RECOMMENDATIONS = 5; + + @Override + public String getName() { + return "more-recommend"; + } + + @Override + public void execute(final ButtonInteractionEvent event) { + final String id = event.getComponent().getId(); + final String[] args = id.split(ARGS_DELIMITER); + final String[] artistGenre = args[1].split(ARTIST_GENRE_DELIMITER); + final String artist = artistGenre[0]; + final String genre = artistGenre.length < 2 ? "" : artistGenre[1]; + final int page = Integer.parseInt(args[2]); + final int nextPage = page + 1; + final int maxIndex = INCREMENT * page; + final int baseIndex = maxIndex - INCREMENT; + + final List tracks = new RecommendationService().getRecommendations(artist, genre, page); + final int maxSize = tracks.size(); + final int maxPage = (int) Math.floor(maxSize / NUM_RECOMMENDATIONS); + + final EmbedBuilder eb = new EmbedBuilder(); + final List trackList = tracks.subList(baseIndex, maxIndex); + if (!trackList.isEmpty()) { + eb + .setTitle("More recommendations based on \"" + artist + "\"") + .setDescription("Here are more recommendations based on your input."); + + trackList.forEach(track -> { + final List trackArtists = Arrays.stream(track.getArtists()) + .map(ArtistSimplified::getName) + .collect(Collectors.toList()); + final String artists = String.join(", ", trackArtists); + + eb.addField(track.getName(), artists, false); + }); + + final MessageEmbed embed = eb.build(); + + final List