From 63ed06a7107261118a19d2f7ef59b0fe3eb5800f Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 17 Feb 2022 17:19:54 +0100 Subject: [PATCH] [YouTube] Differentiate genre mixes from normal mixes Note: genre mixes already worked, now they are just considered as such in various video id extraction and in related items Note 2: now extracting a mix id from a *normal* youtube mix id will fail if the video id wouldn't be exactly 11 characters long --- .../youtube/YoutubeParsingHelper.java | 47 +++++++++++++++---- .../YoutubeMixPlaylistInfoItemExtractor.java | 4 ++ 2 files changed, 43 insertions(+), 8 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 e9cf244a..7fc0aabb 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 @@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.downloader.Response; import org.schabi.newpipe.extractor.exceptions.*; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; +import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.stream.Description; import org.schabi.newpipe.extractor.utils.JsonUtils; import org.schabi.newpipe.extractor.utils.Parser; @@ -246,7 +247,8 @@ public class YoutubeParsingHelper { * @return Whether given id belongs to a YouTube Mix */ public static boolean isYoutubeMixId(@Nonnull final String playlistId) { - return playlistId.startsWith("RD") && !isYoutubeMusicMixId(playlistId); + return playlistId.startsWith("RD") + && !isYoutubeMusicMixId(playlistId); } /** @@ -282,28 +284,57 @@ public class YoutubeParsingHelper { } /** - * @return the video id extracted from the playlist id for Mixes - * @throws ParsingException If the playlistId is a Channel Mix or not a mix. + * Checks if the given playlist id is a YouTube Genre Mix (auto-generated playlist) + * Ids from a YouTube Genre Mix start with "RDGMEM" + * + * @return Whether given id belongs to a YouTube Genre Mix + */ + public static boolean isYoutubeGenreMixId(@Nonnull final String playlistId) { + return playlistId.startsWith("RDGMEM"); + } + + /** + * @param playlistId the playlist id to parse + * @return the {@link PlaylistInfo.PlaylistType} extracted from the playlistId (mix playlist + * types included) + * @throws ParsingException if the playlistId is null or empty, if the playlistId is not a mix, + * if it is a mix but it's not based on a specific stream (this is the + * case for channel or genre mixes) */ @Nonnull - public static String extractVideoIdFromMixId(@Nonnull final String playlistId) + public static String extractVideoIdFromMixId(final String playlistId) throws ParsingException { - if (isYoutubeMyMixId(playlistId)) { + if (isNullOrEmpty(playlistId)) { + throw new ParsingException("Video id could not be determined from empty playlist id"); + + } else if (isYoutubeMyMixId(playlistId)) { return playlistId.substring(4); } else if (isYoutubeMusicMixId(playlistId)) { return playlistId.substring(6); } else if (isYoutubeChannelMixId(playlistId)) { - // Channel mix are build with RMCM{channelId}, so videoId can't be determined - throw new ParsingException("Video id could not be determined from mix id: " + // Channel mixes are of the form RMCM{channelId}, so videoId can't be determined + throw new ParsingException("Video id could not be determined from channel mix id: " + + playlistId); + + } else if (isYoutubeGenreMixId(playlistId)) { + // Genre mixes are of the form RDGMEM{garbage}, so videoId can't be determined + throw new ParsingException("Video id could not be determined from genre mix id: " + playlistId); } else if (isYoutubeMixId(playlistId)) { // normal mix + if (playlistId.length() != 13) { + // Stream YouTube mixes are of the form RD{videoId}, but if videoId is not exactly + // 11 characters then it can't be a video id, hence we are dealing with a different + // type of mix (e.g. genre mixes handled above, of the form RDGMEM{garbage}) + throw new ParsingException("Video id could not be determined from mix id: " + + playlistId); + } return playlistId.substring(2); } else { // not a mix - throw new ParsingException("Video id could not be determined from mix id: " + throw new ParsingException("Video id could not be determined from playlist id: " + playlistId); } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMixPlaylistInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMixPlaylistInfoItemExtractor.java index 279d55ef..f9d11efb 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMixPlaylistInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMixPlaylistInfoItemExtractor.java @@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube.extractors; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getThumbnailUrlFromInfoItem; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeChannelMixId; +import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeGenreMixId; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.isYoutubeMusicMixId; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; @@ -74,8 +75,11 @@ public class YoutubeMixPlaylistInfoItemExtractor implements PlaylistInfoItemExtr return PlaylistInfo.PlaylistType.MIX_MUSIC; } else if (isYoutubeChannelMixId(mixPlaylistId)) { return PlaylistInfo.PlaylistType.MIX_CHANNEL; + } else if (isYoutubeGenreMixId(mixPlaylistId)) { + return PlaylistInfo.PlaylistType.MIX_GENRE; } else { // either a normal mix based on a stream, or a "my mix" (still based on a stream) + // note: if YouTube introduces even more types of mixes, they will default to this return PlaylistInfo.PlaylistType.MIX_STREAM; } } catch (final MalformedURLException e) {