Search in sources :

Example 1 with BasicAudioPlaylist

use of com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist in project lavaplayer by sedmelluq.

the class BandcampAudioSourceManager method loadAlbum.

private AudioItem loadAlbum(String albumUrl) {
    return extractFromPage(albumUrl, (httpClient, text) -> {
        String bandUrl = readBandUrl(text);
        JsonBrowser trackListInfo = readTrackListInformation(text);
        String artist = trackListInfo.get("artist").text();
        List<AudioTrack> tracks = new ArrayList<>();
        for (JsonBrowser trackInfo : trackListInfo.get("trackinfo").values()) {
            tracks.add(extractTrack(trackInfo, bandUrl, artist));
        }
        JsonBrowser albumInfo = readAlbumInformation(text);
        return new BasicAudioPlaylist(albumInfo.get("album_title").text(), tracks, null, false);
    });
}
Also used : BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist) ArrayList(java.util.ArrayList) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack) JsonBrowser(com.sedmelluq.discord.lavaplayer.tools.JsonBrowser)

Example 2 with BasicAudioPlaylist

use of com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist in project lavaplayer by sedmelluq.

the class YoutubeMixProvider method load.

/**
 * Loads tracks from mix in parallel into a playlist entry.
 *
 * @param mixId ID of the mix
 * @param selectedVideoId Selected track, {@link AudioPlaylist#getSelectedTrack()} will return this.
 * @return Playlist of the tracks in the mix.
 */
public AudioPlaylist load(HttpInterface httpInterface, String mixId, String selectedVideoId, Function<AudioTrackInfo, AudioTrack> trackFactory) {
    String playlistTitle = "YouTube mix";
    List<AudioTrack> tracks = new ArrayList<>();
    String mixUrl = "https://www.youtube.com/watch?v=" + selectedVideoId + "&list=" + mixId + PBJ_PARAMETER;
    try (CloseableHttpResponse response = httpInterface.execute(new HttpGet(mixUrl))) {
        HttpClientTools.assertSuccessWithContent(response, "mix response");
        JsonBrowser body = JsonBrowser.parse(response.getEntity().getContent());
        JsonBrowser playlist = body.index(3).get("response").get("contents").get("twoColumnWatchNextResults").get("playlist").get("playlist");
        JsonBrowser title = playlist.get("title");
        if (!title.isNull()) {
            playlistTitle = title.text();
        }
        extractPlaylistTracks(playlist.get("contents"), tracks, trackFactory);
    } catch (IOException e) {
        throw new FriendlyException("Could not read mix page.", SUSPICIOUS, e);
    }
    if (tracks.isEmpty()) {
        throw new FriendlyException("Could not find tracks from mix.", SUSPICIOUS, null);
    }
    AudioTrack selectedTrack = findSelectedTrack(tracks, selectedVideoId);
    return new BasicAudioPlaylist(playlistTitle, tracks, selectedTrack, false);
}
Also used : BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist) HttpGet(org.apache.http.client.methods.HttpGet) ArrayList(java.util.ArrayList) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack) IOException(java.io.IOException) JsonBrowser(com.sedmelluq.discord.lavaplayer.tools.JsonBrowser) FriendlyException(com.sedmelluq.discord.lavaplayer.tools.FriendlyException)

Example 3 with BasicAudioPlaylist

use of com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist in project lavaplayer by sedmelluq.

the class DefaultYoutubePlaylistLoader method buildPlaylist.

private AudioPlaylist buildPlaylist(HttpInterface httpInterface, JsonBrowser json, String selectedVideoId, Function<AudioTrackInfo, AudioTrack> trackFactory) throws IOException {
    JsonBrowser jsonResponse = json.index(1).get("response");
    String errorAlertMessage = findErrorAlert(jsonResponse);
    if (errorAlertMessage != null) {
        throw new FriendlyException(errorAlertMessage, COMMON, null);
    }
    JsonBrowser info = jsonResponse.get("sidebar").get("playlistSidebarRenderer").get("items").index(0).get("playlistSidebarPrimaryInfoRenderer");
    String playlistName = info.get("title").get("runs").index(0).get("text").text();
    JsonBrowser playlistVideoList = jsonResponse.get("contents").get("twoColumnBrowseResultsRenderer").get("tabs").index(0).get("tabRenderer").get("content").get("sectionListRenderer").get("contents").index(0).get("itemSectionRenderer").get("contents").index(0).get("playlistVideoListRenderer").get("contents");
    List<AudioTrack> tracks = new ArrayList<>();
    String continuationsToken = extractPlaylistTracks(playlistVideoList, tracks, trackFactory);
    int loadCount = 0;
    int pageCount = playlistPageCount;
    // Also load the next pages, each result gives us a JSON with separate values for list html and next page loader html
    while (continuationsToken != null && ++loadCount < pageCount) {
        HttpPost post = new HttpPost(REQUEST_URL);
        StringEntity payload = new StringEntity(String.format(REQUEST_PAYLOAD, continuationsToken), "UTF-8");
        post.setEntity(payload);
        try (CloseableHttpResponse response = httpInterface.execute(post)) {
            HttpClientTools.assertSuccessWithContent(response, "playlist response");
            JsonBrowser continuationJson = JsonBrowser.parse(response.getEntity().getContent());
            JsonBrowser playlistVideoListPage = continuationJson.index(1).get("response").get("continuationContents").get("playlistVideoListContinuation");
            if (playlistVideoListPage.isNull()) {
                playlistVideoListPage = continuationJson.get("onResponseReceivedActions").index(0).get("appendContinuationItemsAction").get("continuationItems");
            }
            continuationsToken = extractPlaylistTracks(playlistVideoListPage, tracks, trackFactory);
        }
    }
    return new BasicAudioPlaylist(playlistName, tracks, findSelectedTrack(tracks, selectedVideoId), false);
}
Also used : HttpPost(org.apache.http.client.methods.HttpPost) StringEntity(org.apache.http.entity.StringEntity) BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist) ArrayList(java.util.ArrayList) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack) JsonBrowser(com.sedmelluq.discord.lavaplayer.tools.JsonBrowser) FriendlyException(com.sedmelluq.discord.lavaplayer.tools.FriendlyException)

Example 4 with BasicAudioPlaylist

use of com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist in project FredBoat by Frederikam.

the class TrackSearcher method searchForTracks.

/**
 * @param query         The search term
 * @param cacheMaxAge   Age of acceptable results from cache.
 * @param timeoutMillis How long to wait for each lavaplayer search to answer
 * @param providers     Providers that shall be used for the search. They will be used in the order they are provided, the
 *                      result of the first successful one will be returned
 * @return The result of the search, or an empty list.
 * @throws SearchingException If none of the search providers could give us a result, and there was at least one SearchingException thrown by them
 */
public AudioPlaylist searchForTracks(String query, long cacheMaxAge, int timeoutMillis, List<SearchProvider> providers) throws SearchingException {
    Metrics.searchRequests.inc();
    List<SearchProvider> provs = new ArrayList<>();
    if (providers == null || providers.isEmpty()) {
        log.warn("No search provider provided, defaulting to youtube -> soundcloud.");
        provs.add(SearchProvider.YOUTUBE);
        provs.add(SearchProvider.SOUNDCLOUD);
    } else {
        provs.addAll(providers);
    }
    SearchingException searchingException = null;
    for (SearchProvider provider : provs) {
        // 1. cache
        AudioPlaylist cacheResult = fromCache(provider, query, cacheMaxAge);
        if (cacheResult != null && !cacheResult.getTracks().isEmpty()) {
            log.debug("Loaded search result {} {} from cache", provider, query);
            Metrics.searchHits.labels("cache").inc();
            return cacheResult;
        }
        // 2. lavaplayer todo break up this beautiful construction of ifs and exception handling in a better readable one?
        if (provider != SearchProvider.YOUTUBE || System.currentTimeMillis() > youtubeCooldownUntil) {
            try {
                AudioPlaylist lavaplayerResult = new SearchResultHandler().searchSync(audioPlayerManager, provider, query, timeoutMillis);
                if (!lavaplayerResult.getTracks().isEmpty()) {
                    log.debug("Loaded search result {} {} from lavaplayer", provider, query);
                    // got a search result? cache and return it
                    executor.execute(() -> searchResultService.mergeSearchResult(new SearchResult(audioPlayerManager, provider, query, lavaplayerResult)));
                    Metrics.searchHits.labels("lavaplayer-" + provider.name().toLowerCase()).inc();
                    return lavaplayerResult;
                }
            } catch (Http503Exception e) {
                if (provider == SearchProvider.YOUTUBE) {
                    log.warn("Got a 503 from Youtube. Not hitting it with searches it for {} minutes", TimeUnit.MILLISECONDS.toMinutes(DEFAULT_YOUTUBE_COOLDOWN));
                    youtubeCooldownUntil = System.currentTimeMillis() + DEFAULT_YOUTUBE_COOLDOWN;
                }
                searchingException = e;
            } catch (SearchingException e) {
                searchingException = e;
            }
        }
        // 3. optional: youtube api
        if (provider == SearchProvider.YOUTUBE && (appConfig.isPatronDistribution() || appConfig.isDevDistribution())) {
            try {
                AudioPlaylist youtubeApiResult = youtubeAPI.search(query, MAX_RESULTS, audioPlayerManager.source(YoutubeAudioSourceManager.class));
                if (!youtubeApiResult.getTracks().isEmpty()) {
                    log.debug("Loaded search result {} {} from Youtube API", provider, query);
                    // got a search result? cache and return it
                    executor.execute(() -> searchResultService.mergeSearchResult(new SearchResult(audioPlayerManager, provider, query, youtubeApiResult)));
                    Metrics.searchHits.labels("youtube-api").inc();
                    return youtubeApiResult;
                }
            } catch (SearchingException e) {
                searchingException = e;
            }
        }
    }
    // did we run into searching exceptions that made us end up here?
    if (searchingException != null) {
        Metrics.searchHits.labels("exception").inc();
        throw searchingException;
    }
    // no result with any of the search providers
    Metrics.searchHits.labels("empty").inc();
    return new BasicAudioPlaylist("Search result for: " + query, Collections.emptyList(), null, true);
}
Also used : BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist) YoutubeAudioSourceManager(com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager) ArrayList(java.util.ArrayList) SearchProvider(fredboat.definitions.SearchProvider) SearchResult(fredboat.db.transfer.SearchResult) AudioPlaylist(com.sedmelluq.discord.lavaplayer.track.AudioPlaylist) BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist)

Example 5 with BasicAudioPlaylist

use of com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist in project FredBoat by Frederikam.

the class YoutubeAPI method search.

/**
 * @param query         Search Youtube for this query
 * @param maxResults    Keep this as small as necessary, each of the videos needs to be looked up for more detailed info
 * @param sourceManager The source manager may be used by the tracks to look further information up
 * @return A playlist representing the search results; null if there was an exception
 */
// docs: https://developers.google.com/youtube/v3/docs/search/list
// theres a lot of room for tweaking the searches
public AudioPlaylist search(String query, int maxResults, YoutubeAudioSourceManager sourceManager) throws TrackSearcher.SearchingException {
    JSONObject data;
    String gkey = credentials.getRandomGoogleKey();
    Http.SimpleRequest request = BotController.Companion.getHTTP().get(YOUTUBE_SEARCH, Http.Params.of("key", gkey, "type", "video", "maxResults", Integer.toString(maxResults), "q", query));
    try {
        data = request.asJson();
    } catch (IOException e) {
        throw new TrackSearcher.SearchingException("Youtube API search failed", e);
    }
    // The search contains all values we need, except for the duration :feelsbadman:
    // so we need to do another query for each video.
    List<String> ids = new ArrayList<>(maxResults);
    try {
        JSONArray items = data.getJSONArray("items");
        for (int i = 0; i < items.length(); i++) {
            JSONObject item = items.getJSONObject(i);
            ids.add(item.getJSONObject("id").getString("videoId"));
        }
    } catch (JSONException e) {
        String message = String.format("Youtube search with API key ending on %s for query %s returned unexpected JSON:\n%s", gkey.substring(20), query, data.toString());
        throw new TrackSearcher.SearchingException(message, e);
    }
    List<AudioTrack> tracks = new ArrayList<>();
    for (String id : ids) {
        try {
            YoutubeVideo vid = getVideoFromID(id, true);
            tracks.add(sourceManager.buildTrackObject(id, vid.name, vid.channelTitle, vid.isStream, vid.getDurationInMillis()));
        } catch (RuntimeException e) {
            throw new TrackSearcher.SearchingException("Could not look up details for youtube video with id " + id, e);
        }
    }
    return new BasicAudioPlaylist("Search results for: " + query, tracks, null, true);
}
Also used : BasicAudioPlaylist(com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist) ArrayList(java.util.ArrayList) JSONArray(org.json.JSONArray) JSONException(org.json.JSONException) IOException(java.io.IOException) JSONObject(org.json.JSONObject) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack)

Aggregations

BasicAudioPlaylist (com.sedmelluq.discord.lavaplayer.track.BasicAudioPlaylist)10 ArrayList (java.util.ArrayList)9 AudioTrack (com.sedmelluq.discord.lavaplayer.track.AudioTrack)8 JsonBrowser (com.sedmelluq.discord.lavaplayer.tools.JsonBrowser)6 FriendlyException (com.sedmelluq.discord.lavaplayer.tools.FriendlyException)5 IOException (java.io.IOException)5 CloseableHttpResponse (org.apache.http.client.methods.CloseableHttpResponse)3 HttpGet (org.apache.http.client.methods.HttpGet)2 Element (org.jsoup.nodes.Element)2 YoutubeAudioSourceManager (com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager)1 HttpInterface (com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface)1 AudioItem (com.sedmelluq.discord.lavaplayer.track.AudioItem)1 AudioPlaylist (com.sedmelluq.discord.lavaplayer.track.AudioPlaylist)1 SearchResult (fredboat.db.transfer.SearchResult)1 SearchProvider (fredboat.definitions.SearchProvider)1 ExecutorCompletionService (java.util.concurrent.ExecutorCompletionService)1 HttpPost (org.apache.http.client.methods.HttpPost)1 StringEntity (org.apache.http.entity.StringEntity)1 JSONArray (org.json.JSONArray)1 JSONException (org.json.JSONException)1