From bee24dc8a588ee79a4869504dca25dfedab119fc Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Sun, 21 Jan 2024 20:12:42 -0800 Subject: [PATCH] Initial work for recommendations --- app/src/main/java/musicbot/Listeners.java | 11 +++ app/src/main/java/musicbot/Main.java | 2 + app/src/main/java/musicbot/SpotifyClient.java | 87 +++++++++++++++++++ .../java/musicbot/commands/Recommend.java | 38 ++++++++ 4 files changed, 138 insertions(+) create mode 100644 app/src/main/java/musicbot/SpotifyClient.java create mode 100644 app/src/main/java/musicbot/commands/Recommend.java diff --git a/app/src/main/java/musicbot/Listeners.java b/app/src/main/java/musicbot/Listeners.java index bc820a7..3859de7 100644 --- a/app/src/main/java/musicbot/Listeners.java +++ b/app/src/main/java/musicbot/Listeners.java @@ -13,6 +13,8 @@ public class Listeners extends ListenerAdapter { @Override public void onReady(@NotNull final ReadyEvent event) { + //final Guild guildId = event.getJDA().getGuildById(1197770092243599431L); + event.getJDA().upsertCommand("music", "find music to play").addOptions( new OptionData( OptionType.STRING, @@ -25,5 +27,14 @@ public class Listeners extends ListenerAdapter { "The artist of the song", true) ).queue(); + + event.getJDA().upsertCommand("recommend", "find recommendations for music").addOptions( + new OptionData( + OptionType.STRING, + "artist", + "The name of artist you like", + true + ) + ).queue(); } } diff --git a/app/src/main/java/musicbot/Main.java b/app/src/main/java/musicbot/Main.java index 98dd74e..3a0510a 100644 --- a/app/src/main/java/musicbot/Main.java +++ b/app/src/main/java/musicbot/Main.java @@ -1,6 +1,7 @@ package musicbot; import musicbot.commands.MusicVideo; +import musicbot.commands.Recommend; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; @@ -11,5 +12,6 @@ public class Main { .build(); jda.addEventListener(new Listeners()); jda.addEventListener(new MusicVideo()); + jda.addEventListener(new Recommend()); } } diff --git a/app/src/main/java/musicbot/SpotifyClient.java b/app/src/main/java/musicbot/SpotifyClient.java new file mode 100644 index 0000000..3b9a9cc --- /dev/null +++ b/app/src/main/java/musicbot/SpotifyClient.java @@ -0,0 +1,87 @@ +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 java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class SpotifyClient { + private static final SpotifyApi SPOTIFY_API = new SpotifyApi.Builder() + .setClientId(Token.SPOTIFY_CLIENT_ID) + .setClientSecret(Token.SPOTIFY_CLIENT_SECRET) + .build(); + + private static final ClientCredentialsRequest CLIENT_CREDENTIALS_REQUEST = SPOTIFY_API + .clientCredentials() + .build(); + + public SpotifyClient() { + clientCredentialsSync(); + } + + 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(); + + try { + final Recommendations recommendations = recommendationsRequest.execute(); + System.out.println("Length: " + recommendations.getTracks().length); + + return Arrays.stream(recommendations.getTracks()).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(); + + // Set access token for further "spotifyApi" object usage + SPOTIFY_API.setAccessToken(clientCredentials.getAccessToken()); + + System.out.println("Expires in: " + clientCredentials.getExpiresIn()); + } catch (final IOException | SpotifyWebApiException | ParseException e) { + System.out.println("Error: " + e.getMessage()); + } + } +} diff --git a/app/src/main/java/musicbot/commands/Recommend.java b/app/src/main/java/musicbot/commands/Recommend.java new file mode 100644 index 0000000..548b59b --- /dev/null +++ b/app/src/main/java/musicbot/commands/Recommend.java @@ -0,0 +1,38 @@ +package musicbot.commands; + +import musicbot.SpotifyClient; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.utils.MiscUtil; +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.Track; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +public class Recommend extends ListenerAdapter { + + @Override + public void onSlashCommandInteraction(@NotNull final SlashCommandInteractionEvent event) { + if (!event.getName().equals("recommend")) return; + + final String artist = Objects.requireNonNull(event.getOption("artist")).getAsString(); + 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);/**/ + + event.reply(message).queue(); + } else { + event.reply("Sorry, I can't find any recommendations.").queue(); + } + } +}