From 9038849e18337b87fc235f80f7ac196a7194ccd5 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Tue, 12 Dec 2023 20:00:01 -0800 Subject: Add support for queueing full YouTube playlist via /play Signed-off-by: Pinapelz --- src/main/java/audio/Music.java | 125 +++++++++++++++------------------- src/main/java/utility/URLChecker.java | 12 +++- src/main/java/utility/YouTubeAPI.java | 22 ++++++ 3 files changed, 88 insertions(+), 71 deletions(-) diff --git a/src/main/java/audio/Music.java b/src/main/java/audio/Music.java index a5aec62..f6ed128 100644 --- a/src/main/java/audio/Music.java +++ b/src/main/java/audio/Music.java @@ -124,29 +124,6 @@ public class Music extends ListenerAdapter { System.out.println("I/O Error: " + e.getMessage()); } } - private void fillLoadedPlaylist(String url,String fileName){ - populateFileFromURL(url,fileName); - Scanner s = null; - try { - s = new Scanner(new File("data//"+fileName)); - } catch (FileNotFoundException e) { - System.out.println("File Creation was unsuccessful. Can't access local playlist"); - } - while (true){ - assert s != null; - if (!s.hasNext()) break; - currentlyLoadedPlaylist.add(s.nextLine()); - } - s.close(); - } - public void queueTrackFromLoadedList(SlashCommandInteractionEvent event, int songsToQueue, String url){ - fillLoadedPlaylist(url,"songdb.txt"); - Collections.shuffle(currentlyLoadedPlaylist); - for (int i = 0;i queue = getGuildAudioPlayer(event.getGuild()).scheduler.queue; List trackMenuOptions = new ArrayList(); @@ -198,6 +176,7 @@ public class Music extends ListenerAdapter { } public void shuffleQueue(SlashCommandInteractionEvent event){ Guild guild = event.getGuild(); + if (guild == null) return; GuildMusicManager mng = getGuildAudioPlayer(guild); Queue queue = getGuildAudioPlayer(event.getGuild()).scheduler.queue; if (queue.isEmpty()) @@ -207,7 +186,7 @@ public class Music extends ListenerAdapter { } else{ - ArrayList currentQueue = new ArrayList(queue); //Conversion of queue to arraylist to allow for shuffling + ArrayList currentQueue = new ArrayList<>(queue); //Conversion of queue to arraylist to allow for shuffling Collections.shuffle(currentQueue); BlockingQueue newQueue = new LinkedBlockingQueue<>(); for (Object track : currentQueue) { @@ -219,57 +198,64 @@ public class Music extends ListenerAdapter { } public void playMusic(SlashCommandInteractionEvent event){ - final YouTubeAPI youtubeAPI = new YouTubeAPI(ytapiKey); + final YouTubeAPI youtubeAPI = new YouTubeAPI(ytapiKey); + String userQuery = Objects.requireNonNull(event.getOption("term")).getAsString(); + String urlType = urlCheck.getURLType(userQuery); try { - String userQuery = Objects.requireNonNull(event.getOption("term")).getAsString(); - if (urlCheck.isURL(userQuery) && !urlCheck.getURLType(userQuery).equals("spotify")&&!urlCheck.getURLType(userQuery).equals("spotify-playlist")) { //The term is a URL - event.reply("Found Video: " + userQuery).queue(); - - loadAndPlay((TextChannel) event.getChannel(), userQuery, false); - } - else { - try { - if (urlCheck.getURLType(userQuery).equals("spotify")){ - - event.deferReply().queue(); - event.getHook().sendMessage("Matched Video From Spotify: " + youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(urlCheck.getSpotifyTrackID(userQuery)))).queue(); - loadAndPlay((TextChannel) event.getChannel(), youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(urlCheck.getSpotifyTrackID(userQuery))), true); + switch (urlType) { + case "spotify": + event.deferReply().queue(); + event.getHook().sendMessage("Matched Video From Spotify: " + youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(urlCheck.getSpotifyTrackID(userQuery)))).queue(); + loadAndPlay((TextChannel) event.getChannel(), youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(urlCheck.getSpotifyTrackID(userQuery))), true); + break; + case "spotify-playlist": + event.deferReply().queue(); + PlaylistTrack[] playlist = SpotifyAPI.getPlaylist_Sync(urlCheck.getSpotifyPlaylistID(userQuery)); + if (playlist == null) { + event.getHook().sendMessage("Error: Could not find playlist").queue(); + return; + } else if (playlist.length > MAX_SP_PLAYLIST_SIZE) { + PlaylistTrack[] slicedPlaylist = Arrays.copyOfRange(playlist, 0, MAX_SP_PLAYLIST_SIZE); + event.getHook().sendMessage("Spotify Playlist Detected! But its too long, queueing the first " + MAX_SP_PLAYLIST_SIZE + " songs").queue(); + playlist = slicedPlaylist; + } else { + event.getHook().sendMessage("Spotify Playlist Detected! Queueing " + playlist.length + " songs").queue(); } - else if(urlCheck.getURLType(userQuery).equals("spotify-playlist")){ - event.deferReply().queue(); - //TODO: Add playlist support using selection menu - PlaylistTrack[] playlist = SpotifyAPI.getPlaylist_Sync(urlCheck.getSpotifyPlaylistID(userQuery)); - if (playlist == null){ - event.getHook().sendMessage("Error: Could not find playlist").queue(); - return; - } - else if(playlist.length>MAX_SP_PLAYLIST_SIZE){ - PlaylistTrack[] slicedPlaylist = Arrays.copyOfRange(playlist, 0, MAX_SP_PLAYLIST_SIZE); - event.getHook().sendMessage("Spotify Playlist Detected! But its too long, queueing the first " + MAX_SP_PLAYLIST_SIZE + " songs").queue(); - playlist = slicedPlaylist; - } - else{ - event.getHook().sendMessage("Spotify Playlist Detected! Queueing " + playlist.length + " songs").queue(); - } - for (PlaylistTrack playlistTrack : playlist) { - loadAndPlay((TextChannel) event.getChannel(), youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(playlistTrack.getTrack().getId())), false); - } + for (PlaylistTrack playlistTrack : playlist) { + loadAndPlay((TextChannel) event.getChannel(), youtubeAPI.returnTopVideoURL(SpotifyAPI.getSearchTerm_sync(playlistTrack.getTrack().getId())), false); } - else { - String top_video = youtubeAPI.returnTopVideoURL(userQuery); - event.reply("Found Video: " + top_video).queue(); - loadAndPlay((TextChannel) event.getChannel(), top_video, true); + break; + case "yt": + event.reply("Found Video: " + userQuery).queue(); + loadAndPlay((TextChannel) event.getChannel(), userQuery, false); + break; + case "yt-playlist": + event.deferReply().queue(); + String playlistID = urlCheck.getYouTubePlaylistID(userQuery); + System.out.println(playlistID); + String[] playlistURLS = youtubeAPI.getPlaylistVideoURLs(playlistID, MAX_SP_PLAYLIST_SIZE); + if (playlistURLS.length > MAX_SP_PLAYLIST_SIZE) { + String[] slicedPlaylist = Arrays.copyOfRange(playlistURLS, 0, MAX_SP_PLAYLIST_SIZE); + event.getHook().sendMessage("YouTube Playlist Detected! But its too long, queueing the first " + MAX_SP_PLAYLIST_SIZE + " songs").queue(); + playlistURLS = slicedPlaylist; + } else { + event.getHook().sendMessage("YouTube Playlist Detected! Queueing " + playlistURLS.length + " songs").queue(); } - } catch (IOException e) { - e.printStackTrace(); - event.reply("An error has occured please check the Bot logs for more details").queue(); - } + for (String videoURL : playlistURLS) { + loadAndPlay((TextChannel) event.getChannel(), videoURL, false); + } + break; + default: + System.out.println(urlCheck.getURLType(userQuery) + " was not handled"); + String top_video = youtubeAPI.returnTopVideoURL(userQuery); + event.reply("Found Video: " + top_video).queue(); + loadAndPlay((TextChannel) event.getChannel(), top_video, true); + break; } - - } - catch(Exception e){ - event.reply("Error! Hazukashii! " + e); + } catch (IOException e) { + e.printStackTrace(); + event.reply("An error has occured please check the Bot logs for more details").queue(); } } @@ -341,6 +327,7 @@ public class Music extends ListenerAdapter { String position = getTimestamp(currentTrack.getPosition()); String duration = getTimestamp(currentTrack.getDuration()); switch (currentTrackUrlType) { + case "yt-playlist": case "yt": { //YOUTUBE EMBED EmbedBuilder embed = embedMaker.makeNowPlayingEmbed(currentTrack, position, duration, "https://img.youtube.com/vi/" + currentTrack.getIdentifier() + "/hqdefault.jpg", diff --git a/src/main/java/utility/URLChecker.java b/src/main/java/utility/URLChecker.java index ffea53b..499cca9 100644 --- a/src/main/java/utility/URLChecker.java +++ b/src/main/java/utility/URLChecker.java @@ -5,9 +5,14 @@ public class URLChecker { return term.matches("^(http|https)://.*"); } public String getURLType(String url) { - if (url.matches("^((?:https?:)?\\/\\/)?((?:www|m)\\.)?((?:youtube(-nocookie)?\\.com|youtu.be))(\\/(?:[\\w\\-]+\\?v=|embed\\/|v\\/)?)([\\w\\-]+)(\\S+)?$")) { + if(url.matches("^((?:https?:)?\\/\\/)?((?:www|m)\\.)?youtube\\.com\\/playlist\\?list=([\\w\\-]+)$")){ + System.out.println("yt-playlist"); + return "yt-playlist"; + } + else if (url.matches("^((?:https?:)?\\/\\/)?((?:www|m)\\.)?((?:youtube(-nocookie)?\\.com|youtu.be))(\\/(?:[\\w\\-]+\\?v=|embed\\/|v\\/)?)([\\w\\-]+)(\\S+)?$")) { return "yt"; //Youtube - } else if (url.matches("^(https?:\\/\\/)?(www.)?(m\\.)?soundcloud\\.com\\/[\\w\\-\\.]+(\\/)+[\\w\\-\\.]+/?$")) { + } + else if (url.matches("^(https?:\\/\\/)?(www.)?(m\\.)?soundcloud\\.com\\/[\\w\\-\\.]+(\\/)+[\\w\\-\\.]+/?$")) { return "snd"; } else if (url.matches("^(?:https?:\\/\\/)?(?:www\\.|go\\.)?twitch\\.tv\\/([a-z0-9_]+)($|\\?)")) { return "twitch"; @@ -28,4 +33,7 @@ public class URLChecker { return uriParts[0].replaceAll("https://open.spotify.com/playlist/",""); } + public String getYouTubePlaylistID(String url){ + return url.split("list=")[1]; + } } diff --git a/src/main/java/utility/YouTubeAPI.java b/src/main/java/utility/YouTubeAPI.java index c50897a..982a1d3 100644 --- a/src/main/java/utility/YouTubeAPI.java +++ b/src/main/java/utility/YouTubeAPI.java @@ -9,6 +9,7 @@ import java.io.*; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; public class YouTubeAPI { private String ytapiKey = ""; @@ -43,4 +44,25 @@ public class YouTubeAPI { } } + public String[] getPlaylistVideoURLs(String playlistID, int maxResults) throws IOException{ + String url = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults="+ maxResults +"&playlistId=" + playlistID + "&key=" + ytapiKey; + try (InputStream is = new URL(url).openStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + StringBuilder sb = new StringBuilder(); + int cb; + while ((cb = br.read()) != -1) { + sb.append((char) cb); + } + JSONObject jsonObject = new JSONObject(sb.toString()); + JSONArray jsonArray = jsonObject.getJSONArray("items"); + String[] result = new String[jsonArray.length()]; + for(int i = 0; i < jsonArray.length(); i++){ + result[i] = "https://www.youtube.com/watch?v=" + jsonArray.getJSONObject(i).getJSONObject("snippet").getJSONObject("resourceId").getString("videoId"); + } + return result; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } -- cgit v1.2.3