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 @@ @@ -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 { @@ -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();
}
}

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

@ -1,5 +1,6 @@ @@ -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 { @@ -13,5 +14,6 @@ public class Main {
jda.addEventListener(new Listeners());
jda.addEventListener(new MusicVideo());
jda.addEventListener(new Recommend());
jda.addEventListener(new Genres());
}
}

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

@ -1,20 +1,18 @@ @@ -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 { @@ -37,29 +35,34 @@ public class SpotifyClient {
}
public Optional<Artist> 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<Artist> artists = searchArtistsRequest.execute();
return Arrays.stream(artists.getItems()).findFirst();
} catch (SpotifyWebApiException | ParseException | IOException exception) {
return Optional.empty();
}
}
public List<Track> findRecommendations(final String artistId) {
System.out.println("getting recommendations");
final GetRecommendationsRequest recommendationsRequest = SPOTIFY_API.getRecommendations()
.seed_artists(artistId)
.limit(5)
.build();
public List<Track> 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 { @@ -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() {
try {
final ClientCredentials clientCredentials = CLIENT_CREDENTIALS_REQUEST.execute();

32
app/src/main/java/musicbot/commands/Genres.java

@ -0,0 +1,32 @@ @@ -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 @@ @@ -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 { @@ -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<String> maybeArtistId = findArtistId(artistInput);
final Optional<String> maybeGenre = findGenre(genreInput);
final SpotifyClient spotifyClient = new SpotifyClient();
final Optional<Artist> maybeArtist = spotifyClient.findArtist(artist);
if (maybeArtist.isPresent()) {
final String artistId = maybeArtist.get().getId();
final List<String> 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<Track> 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<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 {
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