Browse Source

add genre recommendation feature

main
Stephanie Gredell 2 years ago
parent
commit
75870de565
  1. 23
      app/src/main/java/musicbot/Listeners.java
  2. 2
      app/src/main/java/musicbot/Main.java
  3. 43
      app/src/main/java/musicbot/SpotifyClient.java
  4. 32
      app/src/main/java/musicbot/commands/Genres.java
  5. 74
      app/src/main/java/musicbot/commands/Recommend.java

23
app/src/main/java/musicbot/Listeners.java

@ -1,21 +1,22 @@
package musicbot; 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.events.ReadyEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public class Listeners extends ListenerAdapter { public class Listeners extends ListenerAdapter {
@Override @Override
public void onReady(@NotNull final ReadyEvent event) { 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( new OptionData(
OptionType.STRING, OptionType.STRING,
"title", "title",
@ -28,13 +29,19 @@ public class Listeners extends ListenerAdapter {
true) true)
).queue(); ).queue();
event.getJDA().upsertCommand("recommend", "find recommendations for music").addOptions( jda.upsertCommand("recommend", "find recommendations for music").addOptions(
new OptionData( new OptionData(
OptionType.STRING, OptionType.STRING,
"artist", "artist",
"The name of artist you like", "Find other songs and artists based on an artist you like"
true ),
new OptionData(
OptionType.STRING,
"genre",
"Find other songs and artists based on a genre you like"
) )
).queue(); ).queue();
jda.upsertCommand("genres", "find recommendations for music").queue();
} }
} }

2
app/src/main/java/musicbot/Main.java

@ -1,5 +1,6 @@
package musicbot; package musicbot;
import musicbot.commands.Genres;
import musicbot.commands.MusicVideo; import musicbot.commands.MusicVideo;
import musicbot.commands.Recommend; import musicbot.commands.Recommend;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
@ -13,5 +14,6 @@ public class Main {
jda.addEventListener(new Listeners()); jda.addEventListener(new Listeners());
jda.addEventListener(new MusicVideo()); jda.addEventListener(new MusicVideo());
jda.addEventListener(new Recommend()); jda.addEventListener(new Recommend());
jda.addEventListener(new Genres());
} }
} }

43
app/src/main/java/musicbot/SpotifyClient.java

@ -1,20 +1,18 @@
package musicbot; package musicbot;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.neovisionaries.i18n.CountryCode;
import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.ParseException;
import se.michaelthelin.spotify.SpotifyApi; import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.exceptions.SpotifyWebApiException; import se.michaelthelin.spotify.exceptions.SpotifyWebApiException;
import se.michaelthelin.spotify.model_objects.credentials.ClientCredentials; 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.Artist;
import se.michaelthelin.spotify.model_objects.specification.Paging; import se.michaelthelin.spotify.model_objects.specification.Paging;
import se.michaelthelin.spotify.model_objects.specification.Recommendations; import se.michaelthelin.spotify.model_objects.specification.Recommendations;
import se.michaelthelin.spotify.model_objects.specification.Track; import se.michaelthelin.spotify.model_objects.specification.Track;
import se.michaelthelin.spotify.requests.authorization.client_credentials.ClientCredentialsRequest; import se.michaelthelin.spotify.requests.authorization.client_credentials.ClientCredentialsRequest;
import se.michaelthelin.spotify.requests.data.browse.GetRecommendationsRequest; 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.search.simplified.SearchArtistsRequest;
import se.michaelthelin.spotify.requests.data.browse.miscellaneous.GetAvailableGenreSeedsRequest;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -37,29 +35,34 @@ public class SpotifyClient {
} }
public Optional<Artist> findArtist(final String artist) { public Optional<Artist> findArtist(final String artist) {
final SearchArtistsRequest searchItemRequest = SPOTIFY_API.searchArtists(artist)
.market(CountryCode.US)
.limit(1)
.build();
try { try {
final SearchArtistsRequest searchArtistsRequest = SPOTIFY_API.searchArtists(artist) final SearchArtistsRequest searchArtistsRequest = SPOTIFY_API.searchArtists(artist)
.limit(1) .limit(1)
.build(); .build();
final Paging<Artist> artists = searchArtistsRequest.execute(); final Paging<Artist> artists = searchArtistsRequest.execute();
return Arrays.stream(artists.getItems()).findFirst(); return Arrays.stream(artists.getItems()).findFirst();
} catch (SpotifyWebApiException | ParseException | IOException exception) { } catch (SpotifyWebApiException | ParseException | IOException exception) {
return Optional.empty(); return Optional.empty();
} }
} }
public List<Track> findRecommendations(final String artistId) { public List<Track> findRecommendations(final String artistId, final String genres) {
System.out.println("getting recommendations"); final GetRecommendationsRequest.Builder recommendationsRequestBuilder = SPOTIFY_API.getRecommendations()
final GetRecommendationsRequest recommendationsRequest = SPOTIFY_API.getRecommendations() .limit(5);
.seed_artists(artistId)
.limit(5) if (!artistId.isEmpty()) {
.build(); recommendationsRequestBuilder
.seed_artists(artistId);
}
if (!genres.isEmpty()) {
recommendationsRequestBuilder
.seed_genres(genres);
}
final GetRecommendationsRequest recommendationsRequest = recommendationsRequestBuilder.build();
try { try {
final Recommendations recommendations = recommendationsRequest.execute(); final Recommendations recommendations = recommendationsRequest.execute();
@ -72,6 +75,18 @@ public class SpotifyClient {
} }
} }
public List<String> 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() { private static void clientCredentialsSync() {
try { try {
final ClientCredentials clientCredentials = CLIENT_CREDENTIALS_REQUEST.execute(); final ClientCredentials clientCredentials = CLIENT_CREDENTIALS_REQUEST.execute();

32
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<String> genres = spotifyClient.findGenres();
final List<List<String>> batches = Lists.partition(genres, 20);
final List<MessageEmbed> 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();
}
}

74
app/src/main/java/musicbot/commands/Recommend.java

@ -1,18 +1,17 @@
package musicbot.commands; package musicbot.commands;
import musicbot.SpotifyClient; 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.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.hooks.ListenerAdapter;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import se.michaelthelin.spotify.model_objects.specification.Artist; 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 se.michaelthelin.spotify.model_objects.specification.Track;
import java.util.List; import java.util.*;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Recommend extends ListenerAdapter { public class Recommend extends ListenerAdapter {
@ -21,18 +20,65 @@ public class Recommend extends ListenerAdapter {
public void onSlashCommandInteraction(@NotNull final SlashCommandInteractionEvent event) { public void onSlashCommandInteraction(@NotNull final SlashCommandInteractionEvent event) {
if (!event.getName().equals("recommend")) return; 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<String> maybeArtistId = findArtistId(artistInput);
final Optional<String> maybeGenre = findGenre(genreInput);
final SpotifyClient spotifyClient = new SpotifyClient(); final SpotifyClient spotifyClient = new SpotifyClient();
final Optional<Artist> maybeArtist = spotifyClient.findArtist(artist);
if (maybeArtist.isPresent()) { final String artistId = maybeArtistId.orElse("");
final String artistId = maybeArtist.get().getId(); final String genre = maybeGenre.orElse("");
final List<String> tracks = spotifyClient.findRecommendations(artistId).stream().map(track -> track.getName()).collect(Collectors.toList()); final List<Track> tracks = spotifyClient.findRecommendations(artistId, genre);
final String message = String.join(", ", tracks);/**/
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<String> 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 { } 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<String> findArtistId(final OptionMapping artistInput) {
if (artistInput == null) {
return Optional.empty();
}
final SpotifyClient spotifyClient = new SpotifyClient();
final Optional<Artist> maybeArtist = spotifyClient.findArtist(artistInput.getAsString());
return maybeArtist.map(Artist::getId);
} }
private Optional<String> findGenre(final OptionMapping genreInput) {
if (genreInput == null) {
return Optional.empty();
}
return Optional.of(genreInput.getAsString());
} }
} }

Loading…
Cancel
Save