@@ -41,6 +41,9 @@ public class YoutubePlaylistExtractor extends PlaylistExtractor {
4141 // Names of some objects in JSON response frequently used in this class
4242 private static final String PLAYLIST_VIDEO_RENDERER = "playlistVideoRenderer" ;
4343 private static final String PLAYLIST_VIDEO_LIST_RENDERER = "playlistVideoListRenderer" ;
44+ private static final String RICH_GRID_RENDERER = "richGridRenderer" ;
45+ private static final String RICH_ITEM_RENDERER = "richItemRenderer" ;
46+ private static final String REEL_ITEM_RENDERER = "reelItemRenderer" ;
4447 private static final String SIDEBAR = "sidebar" ;
4548 private static final String VIDEO_OWNER_RENDERER = "videoOwnerRenderer" ;
4649
@@ -85,10 +88,6 @@ public void onFetchPage(@Nonnull final Downloader downloader) throws IOException
8588 * browse response (the old returns instead a sidebar one).
8689 * </p>
8790 *
88- * <p>
89- * This new playlist UI is currently A/B tested.
90- * </p>
91- *
9291 * @return Whether the playlist response is using only the new playlist design
9392 */
9493 private boolean checkIfResponseIsNewPlaylistInterface () {
@@ -327,17 +326,22 @@ public InfoItemsPage<StreamInfoItem> getInitialPage() throws IOException, Extrac
327326 .map (content -> content .getObject ("itemSectionRenderer" )
328327 .getArray ("contents" )
329328 .getObject (0 ))
330- .filter (contentItemSectionRendererContents ->
331- contentItemSectionRendererContents .has (PLAYLIST_VIDEO_LIST_RENDERER )
332- || contentItemSectionRendererContents .has (
333- "playlistSegmentRenderer" ))
329+ .filter (content -> content .has (PLAYLIST_VIDEO_LIST_RENDERER )
330+ || content .has (RICH_GRID_RENDERER ))
334331 .findFirst ()
335332 .orElse (null );
336333
337- if (videoPlaylistObject != null && videoPlaylistObject .has (PLAYLIST_VIDEO_LIST_RENDERER )) {
338- final JsonArray videosArray = videoPlaylistObject
339- .getObject (PLAYLIST_VIDEO_LIST_RENDERER )
340- .getArray ("contents" );
334+ if (videoPlaylistObject != null ) {
335+ final JsonObject renderer ;
336+ if (videoPlaylistObject .has (PLAYLIST_VIDEO_LIST_RENDERER )) {
337+ renderer = videoPlaylistObject .getObject (PLAYLIST_VIDEO_LIST_RENDERER );
338+ } else if (videoPlaylistObject .has (RICH_GRID_RENDERER )) {
339+ renderer = videoPlaylistObject .getObject (RICH_GRID_RENDERER );
340+ } else {
341+ return new InfoItemsPage <>(collector , null );
342+ }
343+
344+ final JsonArray videosArray = renderer .getArray ("contents" );
341345 collectStreamsFrom (collector , videosArray );
342346
343347 nextPage = getNextPageFrom (videosArray );
@@ -399,14 +403,26 @@ private Page getNextPageFrom(final JsonArray contents)
399403 private void collectStreamsFrom (@ Nonnull final StreamInfoItemsCollector collector ,
400404 @ Nonnull final JsonArray videos ) {
401405 final TimeAgoParser timeAgoParser = getTimeAgoParser ();
402-
403406 videos .stream ()
404407 .filter (JsonObject .class ::isInstance )
405408 .map (JsonObject .class ::cast )
406- .filter (video -> video .has (PLAYLIST_VIDEO_RENDERER ))
407- .map (video -> new YoutubeStreamInfoItemExtractor (
408- video .getObject (PLAYLIST_VIDEO_RENDERER ), timeAgoParser ))
409- .forEachOrdered (collector ::commit );
409+ .forEach (video -> {
410+ if (video .has (PLAYLIST_VIDEO_RENDERER )) {
411+ collector .commit (new YoutubeStreamInfoItemExtractor (
412+ video .getObject (PLAYLIST_VIDEO_RENDERER ), timeAgoParser ));
413+ } else if (video .has (RICH_ITEM_RENDERER )) {
414+ final JsonObject richItemRenderer = video .getObject (RICH_ITEM_RENDERER );
415+ if (richItemRenderer .has ("content" )) {
416+ final JsonObject richItemRendererContent =
417+ richItemRenderer .getObject ("content" );
418+ if (richItemRendererContent .has (REEL_ITEM_RENDERER )) {
419+ collector .commit (new YoutubeReelInfoItemExtractor (
420+ richItemRendererContent .getObject (REEL_ITEM_RENDERER ),
421+ timeAgoParser ));
422+ }
423+ }
424+ }
425+ });
410426 }
411427
412428 @ Nonnull
0 commit comments