diff --git a/app/src/main/java/musicbot/Listeners.java b/app/src/main/java/musicbot/Listeners.java index 3859de7..4fe8346 100644 --- a/app/src/main/java/musicbot/Listeners.java +++ b/app/src/main/java/musicbot/Listeners.java @@ -1,21 +1,22 @@ package musicbot; -import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.events.ReadyEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import org.jetbrains.annotations.NotNull; -import java.util.Objects; - public class Listeners extends ListenerAdapter { + + + @Override public void onReady(@NotNull final ReadyEvent event) { - //final Guild guildId = event.getJDA().getGuildById(1197770092243599431L); + final JDA jda = event.getJDA(); - event.getJDA().upsertCommand("music", "find music to play").addOptions( + jda.upsertCommand("music", "find music to play").addOptions( new OptionData( OptionType.STRING, "title", @@ -28,13 +29,19 @@ public class Listeners extends ListenerAdapter { true) ).queue(); - event.getJDA().upsertCommand("recommend", "find recommendations for music").addOptions( + jda.upsertCommand("recommend", "find recommendations for music").addOptions( new OptionData( OptionType.STRING, "artist", - "The name of artist you like", - true + "Find other songs and artists based on an artist you like" + ), + new OptionData( + OptionType.STRING, + "genre", + "Find other songs and artists based on a genre you like" ) ).queue(); + + jda.upsertCommand("genres", "find recommendations for music").queue(); } } diff --git a/app/src/main/java/musicbot/Main.java b/app/src/main/java/musicbot/Main.java index 3a0510a..45e1ac2 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.commands.Genres; import musicbot.commands.MusicVideo; import musicbot.commands.Recommend; import net.dv8tion.jda.api.JDA; @@ -13,5 +14,6 @@ public class Main { jda.addEventListener(new Listeners()); jda.addEventListener(new MusicVideo()); jda.addEventListener(new Recommend()); + jda.addEventListener(new Genres()); } } diff --git a/app/src/main/java/musicbot/SpotifyClient.java b/app/src/main/java/musicbot/SpotifyClient.java index 3b9a9cc..ba4164b 100644 --- a/app/src/main/java/musicbot/SpotifyClient.java +++ b/app/src/main/java/musicbot/SpotifyClient.java @@ -1,20 +1,18 @@ package musicbot; import com.google.common.collect.ImmutableList; -import com.neovisionaries.i18n.CountryCode; import org.apache.hc.core5.http.ParseException; import se.michaelthelin.spotify.SpotifyApi; import se.michaelthelin.spotify.exceptions.SpotifyWebApiException; import se.michaelthelin.spotify.model_objects.credentials.ClientCredentials; -import se.michaelthelin.spotify.model_objects.special.SearchResult; import se.michaelthelin.spotify.model_objects.specification.Artist; import se.michaelthelin.spotify.model_objects.specification.Paging; import se.michaelthelin.spotify.model_objects.specification.Recommendations; import se.michaelthelin.spotify.model_objects.specification.Track; import se.michaelthelin.spotify.requests.authorization.client_credentials.ClientCredentialsRequest; import se.michaelthelin.spotify.requests.data.browse.GetRecommendationsRequest; -import se.michaelthelin.spotify.requests.data.search.SearchItemRequest; import se.michaelthelin.spotify.requests.data.search.simplified.SearchArtistsRequest; +import se.michaelthelin.spotify.requests.data.browse.miscellaneous.GetAvailableGenreSeedsRequest; import java.io.IOException; import java.util.Arrays; @@ -37,29 +35,34 @@ public class SpotifyClient { } public Optional findArtist(final String artist) { - final SearchArtistsRequest searchItemRequest = SPOTIFY_API.searchArtists(artist) - .market(CountryCode.US) - .limit(1) - .build(); - try { final SearchArtistsRequest searchArtistsRequest = SPOTIFY_API.searchArtists(artist) .limit(1) .build(); final Paging artists = searchArtistsRequest.execute(); + return Arrays.stream(artists.getItems()).findFirst(); } catch (SpotifyWebApiException | ParseException | IOException exception) { return Optional.empty(); } } - public List findRecommendations(final String artistId) { - System.out.println("getting recommendations"); - final GetRecommendationsRequest recommendationsRequest = SPOTIFY_API.getRecommendations() - .seed_artists(artistId) - .limit(5) - .build(); + public List findRecommendations(final String artistId, final String genres) { + final GetRecommendationsRequest.Builder recommendationsRequestBuilder = SPOTIFY_API.getRecommendations() + .limit(5); + + if (!artistId.isEmpty()) { + recommendationsRequestBuilder + .seed_artists(artistId); + } + + if (!genres.isEmpty()) { + recommendationsRequestBuilder + .seed_genres(genres); + } + + final GetRecommendationsRequest recommendationsRequest = recommendationsRequestBuilder.build(); try { final Recommendations recommendations = recommendationsRequest.execute(); @@ -72,6 +75,18 @@ public class SpotifyClient { } } + public List findGenres() { + final GetAvailableGenreSeedsRequest request = SPOTIFY_API.getAvailableGenreSeeds().build(); + + try { + final String[] genres = request.execute(); + return Arrays.stream(genres).collect(Collectors.toList()); + } catch (IOException | SpotifyWebApiException | ParseException e) { + System.out.println("Error: " + e.getMessage()); + return ImmutableList.of(); + } + } + private static void clientCredentialsSync() { try { final ClientCredentials clientCredentials = CLIENT_CREDENTIALS_REQUEST.execute(); diff --git a/app/src/main/java/musicbot/commands/Genres.java b/app/src/main/java/musicbot/commands/Genres.java new file mode 100644 index 0000000..a0a7ee9 --- /dev/null +++ b/app/src/main/java/musicbot/commands/Genres.java @@ -0,0 +1,32 @@ +package musicbot.commands; + +import com.google.common.collect.Lists; +import musicbot.SpotifyClient; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.stream.Collectors; + +public class Genres extends ListenerAdapter { + @Override + public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + if (!event.getName().equals("genres")) return; + + final SpotifyClient spotifyClient = new SpotifyClient(); + final List genres = spotifyClient.findGenres(); + + final List> batches = Lists.partition(genres, 20); + + final List embeds = batches.stream().map(genresList -> { + final EmbedBuilder eb = new EmbedBuilder(); + genresList.forEach(genre -> eb.addField(genre, "", false)); + return eb.build(); + }).collect(Collectors.toList()); + + event.getChannel().sendMessageEmbeds(embeds).queue(); + } +} diff --git a/app/src/main/java/musicbot/commands/Recommend.java b/app/src/main/java/musicbot/commands/Recommend.java index 548b59b..b667fc8 100644 --- a/app/src/main/java/musicbot/commands/Recommend.java +++ b/app/src/main/java/musicbot/commands/Recommend.java @@ -1,18 +1,17 @@ package musicbot.commands; import musicbot.SpotifyClient; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.utils.MiscUtil; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.jetbrains.annotations.NotNull; import se.michaelthelin.spotify.model_objects.specification.Artist; -import se.michaelthelin.spotify.model_objects.specification.Recommendations; +import se.michaelthelin.spotify.model_objects.specification.ArtistSimplified; import se.michaelthelin.spotify.model_objects.specification.Track; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; public class Recommend extends ListenerAdapter { @@ -21,18 +20,65 @@ public class Recommend extends ListenerAdapter { public void onSlashCommandInteraction(@NotNull final SlashCommandInteractionEvent event) { if (!event.getName().equals("recommend")) return; - final String artist = Objects.requireNonNull(event.getOption("artist")).getAsString(); + event.deferReply().queue(); + + final OptionMapping artistInput = event.getOption("artist"); + final OptionMapping genreInput = event.getOption("genre"); + + final Optional maybeArtistId = findArtistId(artistInput); + final Optional maybeGenre = findGenre(genreInput); + final SpotifyClient spotifyClient = new SpotifyClient(); - final Optional maybeArtist = spotifyClient.findArtist(artist); - if (maybeArtist.isPresent()) { - final String artistId = maybeArtist.get().getId(); - final List tracks = spotifyClient.findRecommendations(artistId).stream().map(track -> track.getName()).collect(Collectors.toList()); - final String message = String.join(", ", tracks);/**/ + final String artistId = maybeArtistId.orElse(""); + final String genre = maybeGenre.orElse(""); + final List tracks = spotifyClient.findRecommendations(artistId, genre); + + final EmbedBuilder eb = new EmbedBuilder(); + if (!tracks.isEmpty()) { + + eb + .setTitle("Recommendations") + .setDescription("Here are a list of recommendations based on your input. " + + "It will help you find new music to listen to."); - event.reply(message).queue(); + tracks.forEach(track -> { + List trackArtists = Arrays.stream(track.getArtists()) + .map(ArtistSimplified::getName) + .collect(Collectors.toList()); + String artists = String.join(", ", trackArtists); + + eb.addField(track.getName(), artists, false); + }); + + MessageEmbed embed = eb.build(); + + event.getHook().sendMessageEmbeds(embed).queue(); } else { - event.reply("Sorry, I can't find any recommendations.").queue(); + eb.setTitle("No recommendations found"); + final MessageEmbed embed = eb.build(); + + event.getHook().sendMessageEmbeds(embed).queue(); + } + + } + + private Optional findArtistId(final OptionMapping artistInput) { + if (artistInput == null) { + return Optional.empty(); + } + + final SpotifyClient spotifyClient = new SpotifyClient(); + final Optional maybeArtist = spotifyClient.findArtist(artistInput.getAsString()); + + return maybeArtist.map(Artist::getId); + } + + private Optional findGenre(final OptionMapping genreInput) { + if (genreInput == null) { + return Optional.empty(); } + + return Optional.of(genreInput.getAsString()); } }