From 23d098780b9c896317abde6e89236b63d403d825 Mon Sep 17 00:00:00 2001 From: Sebastien Date: Thu, 29 Nov 2018 18:37:40 +0200 Subject: [PATCH] Add playlist search + update lavaplayer + materialize --- build.gradle | 2 +- .../java/net/Broken/Commands/YtSearch.java | 2 +- .../Broken/RestApi/MusicWebAPIController.java | 4 +- .../Broken/audio/AudioPlayerSendHandler.java | 2 +- .../Broken/audio/Youtube/SearchResult.java | 5 +- .../Broken/audio/Youtube/YoutubeTools.java | 66 ++++++--- src/main/resources/static/css/materialize.css | 4 +- src/main/resources/static/js/materialize.js | 38 +++-- src/main/resources/static/js/music.js | 17 ++- src/main/resources/templates/music.html | 137 ++++++++++-------- 10 files changed, 173 insertions(+), 104 deletions(-) diff --git a/build.gradle b/build.gradle index 3ed489b..cc7594a 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ dependencies { exclude group:"org.springframework.boot", module: "spring-boot-starter-logging" } compile("org.springframework.boot:spring-boot-starter-log4j2") - compile("com.sedmelluq:lavaplayer:1.2.49") + compile("com.sedmelluq:lavaplayer:1.3.10") compile 'net.dv8tion:JDA:3.6.0_354' compile group: 'org.json', name: 'json', version: '20160810' compile 'org.springframework.security:spring-security-web:5.0.1.RELEASE' diff --git a/src/main/java/net/Broken/Commands/YtSearch.java b/src/main/java/net/Broken/Commands/YtSearch.java index 9c6232c..c009c35 100644 --- a/src/main/java/net/Broken/Commands/YtSearch.java +++ b/src/main/java/net/Broken/Commands/YtSearch.java @@ -31,7 +31,7 @@ public class YtSearch implements Commande { new MessageTimeOut(MainBot.messageTimeOut, message, event.getMessage()).start(); }else { try { - ArrayList result = youtubeT.search(args[0], 5); + ArrayList result = youtubeT.search(args[0], 5, false); for(SearchResult item : result){ event.getChannel().sendMessage(EmbedMessageUtils.searchResult(item)).queue(); } diff --git a/src/main/java/net/Broken/RestApi/MusicWebAPIController.java b/src/main/java/net/Broken/RestApi/MusicWebAPIController.java index 747778a..1a11f43 100644 --- a/src/main/java/net/Broken/RestApi/MusicWebAPIController.java +++ b/src/main/java/net/Broken/RestApi/MusicWebAPIController.java @@ -200,12 +200,12 @@ public class MusicWebAPIController { } @RequestMapping(value = "/search", method = RequestMethod.GET) - public ResponseEntity> search(@CookieValue("token") String token, @RequestParam(value = "query") String query ){ + public ResponseEntity> search(@CookieValue("token") String token, @RequestParam(value = "query") String query, @RequestParam(value = "playlist") boolean playlist ){ if(token != null) { try { UserEntity user = userUtils.getUserWithApiToken(userRepository, token); YoutubeTools youtubeTools = YoutubeTools.getInstance(); - ArrayList result = youtubeTools.search(query, 25); + ArrayList result = youtubeTools.search(query, 25, playlist); return new ResponseEntity<>(result, HttpStatus.OK); }catch (UnknownTokenException e){ diff --git a/src/main/java/net/Broken/audio/AudioPlayerSendHandler.java b/src/main/java/net/Broken/audio/AudioPlayerSendHandler.java index 29221dc..89fe125 100644 --- a/src/main/java/net/Broken/audio/AudioPlayerSendHandler.java +++ b/src/main/java/net/Broken/audio/AudioPlayerSendHandler.java @@ -37,7 +37,7 @@ public class AudioPlayerSendHandler implements AudioSendHandler { lastFrame = audioPlayer.provide(); } - byte[] data = lastFrame != null ? lastFrame.data : null; + byte[] data = lastFrame != null ? lastFrame.getData() : null; lastFrame = null; return data; diff --git a/src/main/java/net/Broken/audio/Youtube/SearchResult.java b/src/main/java/net/Broken/audio/Youtube/SearchResult.java index 1a36538..7aa75aa 100644 --- a/src/main/java/net/Broken/audio/Youtube/SearchResult.java +++ b/src/main/java/net/Broken/audio/Youtube/SearchResult.java @@ -11,7 +11,10 @@ public class SearchResult { public String duration; public SearchResult(com.google.api.services.youtube.model.SearchResult result, String duration){ - id = result.getId().getVideoId(); + if(result.getId().getVideoId() == null) + id = result.getId().getPlaylistId(); + else + id = result.getId().getVideoId(); title = result.getSnippet().getTitle(); description = result.getSnippet().getDescription(); publishedAt = result.getSnippet().getPublishedAt().toString(); diff --git a/src/main/java/net/Broken/audio/Youtube/YoutubeTools.java b/src/main/java/net/Broken/audio/Youtube/YoutubeTools.java index 369365e..469fbf3 100644 --- a/src/main/java/net/Broken/audio/Youtube/YoutubeTools.java +++ b/src/main/java/net/Broken/audio/Youtube/YoutubeTools.java @@ -3,10 +3,8 @@ package net.Broken.audio.Youtube; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.services.youtube.YouTube; -import com.google.api.services.youtube.model.SearchListResponse; +import com.google.api.services.youtube.model.*; import com.google.api.services.youtube.model.SearchResult; -import com.google.api.services.youtube.model.Video; -import com.google.api.services.youtube.model.VideoListResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -81,10 +79,13 @@ public class YoutubeTools { } - public ArrayList search(String query, long max) throws IOException { + public ArrayList search(String query, long max, boolean playlist) throws IOException { YouTube youTube = getYoutubeService(); YouTube.Search.List searchList = youTube.search().list("snippet"); - searchList.setType("video"); + if(playlist) + searchList.setType("playlist"); + else + searchList.setType("video"); searchList.setSafeSearch("none"); searchList.setMaxResults(max); searchList.setQ(query); @@ -94,30 +95,55 @@ public class YoutubeTools { SearchListResponse response = searchList.execute(); StringBuilder idString = new StringBuilder(); - for(SearchResult item : response.getItems()){ - idString.append(item.getId().getVideoId()).append(","); - } - HashMap videoHashMap = new HashMap<>(); - YouTube.Videos.List video = youTube.videos().list("contentDetails"); - video.setId(idString.toString()); - video.setKey(apiKey); - VideoListResponse videoResponse = video.execute(); - for(Video item : videoResponse.getItems()){ - videoHashMap.put(item.getId(), item); + if(playlist){ + for(SearchResult item : response.getItems()){ + idString.append(item.getId().getPlaylistId()).append(","); + } + HashMap playlistHashMap = new HashMap<>(); + YouTube.Playlists.List list = youTube.playlists().list("contentDetails"); + list.setId(idString.toString()); + list.setKey(apiKey); + PlaylistListResponse playlistResponse = list.execute(); + for( Playlist item : playlistResponse.getItems()){ + playlistHashMap.put(item.getId(), item); + } + ArrayList finalResult = new ArrayList<>(); + for(SearchResult item : response.getItems()){ + logger.trace(item.getSnippet().getTitle()); + finalResult.add(new net.Broken.audio.Youtube.SearchResult(item, playlistHashMap.get(item.getId().getPlaylistId()).getContentDetails().getItemCount().toString()+ " Video(s)")); + + } + return finalResult; } - ArrayList finalResult = new ArrayList<>(); - for(SearchResult item : response.getItems()){ - logger.trace(item.getSnippet().getTitle()); - finalResult.add(new net.Broken.audio.Youtube.SearchResult(item, videoHashMap.get(item.getId().getVideoId()).getContentDetails().getDuration())); + else{ + for(SearchResult item : response.getItems()){ + idString.append(item.getId().getVideoId()).append(","); + } + HashMap videoHashMap = new HashMap<>(); + YouTube.Videos.List video = youTube.videos().list("contentDetails"); + video.setId(idString.toString()); + video.setKey(apiKey); + VideoListResponse videoResponse = video.execute(); + for(Video item : videoResponse.getItems()){ + videoHashMap.put(item.getId(), item); + } + ArrayList finalResult = new ArrayList<>(); + for(SearchResult item : response.getItems()){ + logger.trace(item.getSnippet().getTitle()); + finalResult.add(new net.Broken.audio.Youtube.SearchResult(item, videoHashMap.get(item.getId().getVideoId()).getContentDetails().getDuration())); + } + return finalResult; } - return finalResult; + + + } diff --git a/src/main/resources/static/css/materialize.css b/src/main/resources/static/css/materialize.css index 416777f..bc6c1fe 100644 --- a/src/main/resources/static/css/materialize.css +++ b/src/main/resources/static/css/materialize.css @@ -1,5 +1,5 @@ /*! - * Materialize v1.0.0-rc.2 (http://materializecss.com) + * Materialize v1.0.0 (http://materializecss.com) * Copyright 2014-2017 Materialize * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) */ @@ -6551,7 +6551,7 @@ textarea.materialize-textarea + label:after, .select-wrapper + label:after { transform-origin: 0 0; } -.input-field > input[type]:-webkit-autofill:not(.browser-default) + label, +.input-field > input[type]:-webkit-autofill:not(.browser-default):not([type="search"]) + label, .input-field > input[type=date]:not(.browser-default) + label, .input-field > input[type=time]:not(.browser-default) + label { -webkit-transform: translateY(-14px) scale(0.8); diff --git a/src/main/resources/static/js/materialize.js b/src/main/resources/static/js/materialize.js index 7e218e6..1e18382 100644 --- a/src/main/resources/static/js/materialize.js +++ b/src/main/resources/static/js/materialize.js @@ -1,5 +1,5 @@ /*! - * Materialize v1.0.0-rc.2 (http://materializecss.com) + * Materialize v1.0.0 (http://materializecss.com) * Copyright 2014-2017 Materialize * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) */ @@ -1084,6 +1084,8 @@ if (typeof define === 'function' && define.amd) { exports.default = M; } +M.version = '1.0.0'; + M.keys = { TAB: 9, ENTER: 13, @@ -2507,7 +2509,11 @@ $jscomp.polyfill = function (e, r, p, m) { var $activatableElement = $(focusedElement).find('a, button').first(); // Click a or button tag if exists, otherwise click li tag - !!$activatableElement.length ? $activatableElement[0].click() : focusedElement.click(); + if (!!$activatableElement.length) { + $activatableElement[0].click(); + } else if (!!focusedElement) { + focusedElement.click(); + } // Close dropdown on ESC } else if (e.which === M.keys.ESC && this.isOpen) { @@ -2687,8 +2693,7 @@ $jscomp.polyfill = function (e, r, p, m) { // onOpenEnd callback if (typeof _this11.options.onOpenEnd === 'function') { - var elem = anim.animatables[0].target; - _this11.options.onOpenEnd.call(elem, _this11.el); + _this11.options.onOpenEnd.call(_this11, _this11.el); } } }); @@ -2719,7 +2724,6 @@ $jscomp.polyfill = function (e, r, p, m) { // onCloseEnd callback if (typeof _this12.options.onCloseEnd === 'function') { - var elem = anim.animatables[0].target; _this12.options.onCloseEnd.call(_this12, _this12.el); } } @@ -2849,7 +2853,7 @@ $jscomp.polyfill = function (e, r, p, m) { Dropdown._dropdowns = []; - window.M.Dropdown = Dropdown; + M.Dropdown = Dropdown; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Dropdown, 'dropdown', 'M_Dropdown'); @@ -4420,7 +4424,7 @@ $jscomp.polyfill = function (e, r, p, m) { return Tabs; }(Component); - window.M.Tabs = Tabs; + M.Tabs = Tabs; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Tabs, 'tabs', 'M_Tabs'); @@ -6090,7 +6094,7 @@ $jscomp.polyfill = function (e, r, p, m) { Sidenav._sidenavs = []; - window.M.Sidenav = Sidenav; + M.Sidenav = Sidenav; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Sidenav, 'sidenav', 'M_Sidenav'); @@ -11833,10 +11837,20 @@ $jscomp.polyfill = function (e, r, p, m) { // Add callback for centering selected option when dropdown content is scrollable dropdownOptions.onOpenEnd = function (el) { var selectedOption = $(_this71.dropdownOptions).find('.selected').first(); - if (_this71.dropdown.isScrollable && selectedOption.length) { - var scrollOffset = selectedOption[0].getBoundingClientRect().top - _this71.dropdownOptions.getBoundingClientRect().top; // scroll to selected option - scrollOffset -= _this71.dropdownOptions.clientHeight / 2; // center in dropdown - _this71.dropdownOptions.scrollTop = scrollOffset; + + if (selectedOption.length) { + // Focus selected option in dropdown + M.keyDown = true; + _this71.dropdown.focusedIndex = selectedOption.index(); + _this71.dropdown._focusFocusedItem(); + M.keyDown = false; + + // Handle scrolling to selected option + if (_this71.dropdown.isScrollable) { + var scrollOffset = selectedOption[0].getBoundingClientRect().top - _this71.dropdownOptions.getBoundingClientRect().top; // scroll to selected option + scrollOffset -= _this71.dropdownOptions.clientHeight / 2; // center in dropdown + _this71.dropdownOptions.scrollTop = scrollOffset; + } } }; diff --git a/src/main/resources/static/js/music.js b/src/main/resources/static/js/music.js index e739f42..6e2eb1b 100644 --- a/src/main/resources/static/js/music.js +++ b/src/main/resources/static/js/music.js @@ -41,6 +41,7 @@ $(document).ready(function () { modal_loading = M.Modal.init($('#modal_loading').get(0), {dismissible: false}); modal_loading.open(); + $('#tabs-swipe-demo').tabs(); $('.dropdown-button').dropdown({ @@ -171,7 +172,6 @@ function getCurentMusic() { } } - clearInterval(interval); if (savedPlaylist != null) { $('#playlist_list').empty(); savedPlaylist = null; @@ -431,14 +431,21 @@ function search() { load.removeClass("hide"); load.addClass("scale-in"); - $.get("/api/music/search?query=" + input_search.val(), (data) => { + $.get("/api/music/search?query=" + input_search.val() + "&playlist=" + $("#playlistSearch").is(':checked'), (data) => { list.empty(); + let url; + if($("#playlistSearch").is(':checked')){ + url = "https://www.youtube.com/playlist?list=" + } + else + url = "https://youtube.com/watch?v="; + data.forEach((item) => { let html = "
  • " + " \"\"" + - " " + item["title"] + "" + + " " + item["title"] + "" + "

    " + item["channelTittle"] + " ║ " + item["publishedAt"].substr(0, item["publishedAt"].indexOf('T')) + "
    " + ytTimeToTime(item["duration"]) + "

    " + " add_circle_outline" + @@ -495,7 +502,7 @@ function addListClick(event) { let command = { command: "ADD", url: button.id, - playlistLimit: $('#limit_range').val(), + playlistLimit: "300", onHead: !$('#bottom').is(':checked') }; sendCommand(command, false); @@ -507,6 +514,8 @@ function ytTimeToTime(duration) { let seconds; if (duration === "PT0S") return "🔴 LIVE"; + if(duration.endsWith("Video(s)")) + return duration; if (duration.includes("H")) hours = parseInt(duration.match(/\d*H/)[0].replace("H", ""), 10); else diff --git a/src/main/resources/templates/music.html b/src/main/resources/templates/music.html index aed3984..8d4d2fc 100644 --- a/src/main/resources/templates/music.html +++ b/src/main/resources/templates/music.html @@ -16,22 +16,23 @@