From 66cdca8f0d9afd1e93e735e26950ffd3bee3e466 Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Thu, 30 Sep 2021 20:49:28 +0100 Subject: [PATCH] Add music searching support. --- src/main/java/moe/nekojimi/chords/Main.java | 165 ++++++++++++++++---- 1 file changed, 138 insertions(+), 27 deletions(-) diff --git a/src/main/java/moe/nekojimi/chords/Main.java b/src/main/java/moe/nekojimi/chords/Main.java index 5d723a7..1ecbfbf 100644 --- a/src/main/java/moe/nekojimi/chords/Main.java +++ b/src/main/java/moe/nekojimi/chords/Main.java @@ -5,10 +5,17 @@ */ package moe.nekojimi.chords; +import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import javax.security.auth.login.LoginException; +import moe.nekojimi.musicsearcher.Query; +import moe.nekojimi.musicsearcher.Result; +import moe.nekojimi.musicsearcher.providers.MetaSearcher; +import moe.nekojimi.musicsearcher.providers.Searcher; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.*; @@ -26,10 +33,18 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; public class Main extends ListenerAdapter { + private static final double SEARCH_SCORE_THRESHOLD_AUTOPLAY = 0.9; + private static final double SEARCH_SCORE_THRESHOLD_DISPLAY = 0.6; + private MusicHandler musicHandler; - private Downloader downloader; + private final Downloader downloader; + private final Searcher searcher; private JDA jda; + private List lastSearchResults; + + private int trackNumber = 1; + /** * @param args the command line arguments */ @@ -68,16 +83,18 @@ public class Main extends ListenerAdapter downloader.setMessageHandler((Song song, Exception ex) -> { TextChannel channel = jda.getTextChannelById(song.getRequestedIn()); + String bracketNo = "[" + song.getNumber() + "] "; if (channel != null) if (ex == null) if (song.getLocation() != null) - channel.sendMessage("Finished downloading track for " + song.getRequestedBy() + ", added to queue!").queue(); + channel.sendMessage(bracketNo + "Finished downloading " + song + " for " + song.getRequestedBy() + ", added to queue!").queue(); else - channel.sendMessage("Now downloading track for " + song.getRequestedBy() + " ...").queue(); + channel.sendMessage(bracketNo + "Now downloading " + song + " for " + song.getRequestedBy() + " ...").queue(); else - channel.sendMessage("Failed to download track for " + song.getRequestedBy() + "! Reason: " + ex.getMessage()).queue(); + channel.sendMessage(bracketNo + "Failed to download " + song + " for " + song.getRequestedBy() + "! Reason: " + ex.getMessage()).queue(); }); + searcher = MetaSearcher.loadYAML(new File("searchproviders.yml")); } public void setJda(JDA jda) @@ -148,7 +165,7 @@ public class Main extends ListenerAdapter // onConnecting(channel, event.getChannel()); // Tell the user about our success // } else // onUnknownChannel(event.getChannel(), "your voice channel"); // Tell the user about our failure - onJoinCommand(event, member.getGuild(), channel.getId()); + onJoinCommand(event, member.getGuild(), channel.getName()); } /** @@ -188,26 +205,93 @@ public class Main extends ListenerAdapter { try { - Song song = new Song(new URL(arg)); - song.setRequestedBy(event.getAuthor().getName()); - song.setRequestedIn(event.getChannel().getId()); -// event.getChannel().sendMessage("Downloading ...").queue(); - downloader.accept(song); -// boolean ok = downloadSong(song); -// if (ok) -// { -// musicHandler.addSong(song); -// if (musicHandler.isPlaying()) -// musicHandler.setPlaying(true); -// event.getChannel().sendMessage("Downloaded and added to queue!").queue(); -// } - - } catch (MalformedURLException ex) + final URL url = new URL(arg); + queueDownload(url, event); + + } catch (MalformedURLException mux) { - event.getChannel().sendMessage("That's not a valid URL you idiot! " + ex.getMessage()).queue(); + // not a URL, try parsing it as a search result + if (lastSearchResults != null && !lastSearchResults.isEmpty()) + { + try + { + int index = Integer.parseInt(arg); + int size = lastSearchResults.size(); + if (index >= 1 && index <= size) + { + Result res = lastSearchResults.get(index - 1); + queueDownload(res.getLink(), event); +// event.getChannel().sendMessage("Song removed.").queue(); + } else if (size > 1) + event.getChannel().sendMessage("That's not a number between 1 and " + size + "!").queue(); + else if (size == 1) + event.getChannel().sendMessage("There's only one song and that's not one of them!").queue(); + + return; + } catch (NumberFormatException nfx) + { +// event.getChannel().sendMessage(arg + " isn't a number!").queue(); + } + } + + // otherwise, try searching + CompletableFuture> search = searcher.search(Query.fullText(arg)); + event.getChannel().sendMessage("Searching for \"" + arg + "\" ...").queue(); + search.orTimeout(30, TimeUnit.SECONDS).whenCompleteAsync((List results, Throwable exec) -> + { + if (exec != null) + { + event.getChannel().sendMessage("Failed to search! Reason: " + exec.getMessage()).queue(); + return; + } + + lastSearchResults = results; + + if (results.isEmpty()) + { + event.getChannel().sendMessage("Found nothing! :(").queue(); + return; + } + + if (results.get(0).getScore() >= SEARCH_SCORE_THRESHOLD_AUTOPLAY) + { + queueDownload(results.get(0).getLink(), event); + return; + } + + String resultString = ">>> :mag: __Search results:__\n"; + int i = 1; + for (Result result : results) + { + if (result.getScore() <= SEARCH_SCORE_THRESHOLD_DISPLAY && i > 5) + break; + if (i > 10) + break; + resultString += "**" + i + ":** " + + "[" + result.getSourceAbbr() + "] " + + "*" + result.getTitle() + "* " + + "by " + (result.getArtist() != null ? result.getArtist().trim() : "unknown") + " " + // + (result.getAlbum() != null ? "from the album *" + result.getAlbum().trim() + "*" : "") + + "\n"; + i++; + } + resultString += "Type eg. `!play 1` to select"; + event.getChannel().sendMessage(resultString).queue(); + }); +// event.getChannel().sendMessage("That's not a valid URL you idiot! " + ex.getMessage()).queue(); } } + private void queueDownload(final URL url, GuildMessageReceivedEvent event) + { + Song song = new Song(url); + song.setRequestedBy(event.getAuthor().getName()); + song.setRequestedIn(event.getChannel().getId()); + song.setNumber(trackNumber); + trackNumber++; + downloader.accept(song); + } + private void onRestartCommand(GuildMessageReceivedEvent event) { // TODO: this needs to clear the current data queue @@ -229,13 +313,40 @@ public class Main extends ListenerAdapter private void onQueueCommand(GuildMessageReceivedEvent event, Guild guild) { - Queue songQueue = musicHandler.getSongQueue(); - String message = new String(); + String message = ">>> "; int i = 1; - message += "Now playing: " + musicHandler.getCurrentSong() + "\n"; - message += "---\n"; - for (Song song : songQueue) - message += (i) + ": " + song + "\n"; + + final Song currentSong = musicHandler.getCurrentSong(); + if (currentSong != null) + message += ":notes: **Now playing: " + currentSong + "**\n"; + else + message += ":mute: **Not playing anything right now.**\n"; + + final Queue songQueue = musicHandler.getSongQueue(); + if (!songQueue.isEmpty()) + { + message += "__Ready to play:__\n"; + for (Song song : songQueue) + { + message += ":bread: **" + (i) + ":** " + song + "\n"; + i++; + } + } + + final List downloadQueue = downloader.getDownloadQueue(); + if (!downloadQueue.isEmpty()) + { + message += "__Downloading:__\n"; + for (Song song : downloadQueue) + { + message += ":inbox_tray: **" + (i) + ":** " + song + "\n"; + i++; + } + } + + if (downloadQueue.isEmpty() && songQueue.isEmpty()) + message += ":mailbox_with_no_mail: The track queue is empty."; + // :inbox_tray: event.getChannel().sendMessage(message).queue(); }