From adfad086ac21a8aa7af375bbf16ab2761592dc64 Mon Sep 17 00:00:00 2001 From: AudricV <74829229+AudricV@users.noreply.github.com> Date: Fri, 22 Jul 2022 17:28:39 +0200 Subject: [PATCH] [YouTube] Add utility methods to get images from InfoItems and thumbnails arrays Unmodifiable lists of Images are returned, parsed from a given YouTube "thumbnails" JSON array. These methods will be used in all YouTube extractors and InfoItems, as the structures between content types (videos, channels, playlists, ...) are common. --- .../youtube/YoutubeParsingHelper.java | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java index aec550897..1bce2c2f8 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java @@ -33,6 +33,9 @@ import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonWriter; import org.jsoup.nodes.Entities; + +import org.schabi.newpipe.extractor.Image; +import org.schabi.newpipe.extractor.Image.ResolutionLevel; import org.schabi.newpipe.extractor.MetaInfo; import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException; @@ -69,6 +72,7 @@ import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -1133,17 +1137,61 @@ public final class YoutubeParsingHelper { return result; } - public static String getThumbnailUrlFromInfoItem(final JsonObject infoItem) + /** + * Get thumbnails from a {@link JsonObject} representing a YouTube + * {@link org.schabi.newpipe.extractor.InfoItem InfoItem}. + * + *

+ * Thumbnails are got from the {@code thumbnails} {@link JsonArray} inside the {@code thumbnail} + * {@link JsonObject} of the YouTube {@link org.schabi.newpipe.extractor.InfoItem InfoItem}, + * using {@link #getImagesFromThumbnailsArray(JsonArray)}. + *

+ * + * @param infoItem a YouTube {@link org.schabi.newpipe.extractor.InfoItem InfoItem} + * @return an unmodifiable list of {@link Image}s found in the {@code thumbnails} + * {@link JsonArray} + * @throws ParsingException if an exception occurs when + * {@link #getImagesFromThumbnailsArray(JsonArray)} is executed + */ + @Nonnull + public static List getThumbnailsFromInfoItem(@Nonnull final JsonObject infoItem) throws ParsingException { - // TODO: Don't simply get the first item, but look at all thumbnails and their resolution try { - return fixThumbnailUrl(infoItem.getObject("thumbnail").getArray("thumbnails") - .getObject(0).getString("url")); + return getImagesFromThumbnailsArray(infoItem.getObject("thumbnail") + .getArray("thumbnails")); } catch (final Exception e) { - throw new ParsingException("Could not get thumbnail url", e); + throw new ParsingException("Could not get thumbnails from InfoItem", e); } } + /** + * Get images from a YouTube {@code thumbnails} {@link JsonArray}. + * + *

+ * The properties of the {@link Image}s created will be set using the corresponding ones of + * thumbnail items. + *

+ * + * @param thumbnails a YouTube {@code thumbnails} {@link JsonArray} + * @return an unmodifiable list of {@link Image}s extracted from the given {@link JsonArray} + */ + @Nonnull + public static List getImagesFromThumbnailsArray( + @Nonnull final JsonArray thumbnails) { + return thumbnails.stream() + .filter(JsonObject.class::isInstance) + .map(JsonObject.class::cast) + .filter(thumbnail -> !isNullOrEmpty(thumbnail.getString("url"))) + .map(thumbnail -> { + final int height = thumbnail.getInt("height", Image.HEIGHT_UNKNOWN); + return new Image(fixThumbnailUrl(thumbnail.getString("url")), + height, + thumbnail.getInt("width", Image.WIDTH_UNKNOWN), + ResolutionLevel.fromHeight(height)); + }) + .collect(Collectors.toUnmodifiableList()); + } + @Nonnull public static String getValidJsonResponseBody(@Nonnull final Response response) throws ParsingException, MalformedURLException {