From 0abc2a4069468286fc02e5830d66792297f65f2b Mon Sep 17 00:00:00 2001 From: Holger Schmidt Date: Thu, 12 Dec 2024 18:55:54 +0100 Subject: [PATCH] Fix playlist search response extraction (#843) --- YoutubeExplode.Tests/SearchSpecs.cs | 11 +++++ YoutubeExplode/Bridge/SearchResponse.cs | 59 ++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/YoutubeExplode.Tests/SearchSpecs.cs b/YoutubeExplode.Tests/SearchSpecs.cs index 1838ed21..61a92201 100644 --- a/YoutubeExplode.Tests/SearchSpecs.cs +++ b/YoutubeExplode.Tests/SearchSpecs.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using FluentAssertions; using Xunit; @@ -100,6 +101,16 @@ public async Task I_can_get_playlist_results_from_a_search_query() // Assert playlists.Should().NotBeEmpty(); + + var last = playlists.Last(); + + last.Title.Should().NotBeNullOrWhiteSpace(); + last.Author.Should().NotBeNull(); + last.Thumbnails.Should().NotBeEmpty(); + + var lastThumb = last.Thumbnails.Last(); + lastThumb.Url.Should().NotBeNullOrWhiteSpace(); + lastThumb.Resolution.Should().NotBeSameAs(default(Resolution)); } [Fact] diff --git a/YoutubeExplode/Bridge/SearchResponse.cs b/YoutubeExplode/Bridge/SearchResponse.cs index 51883fe6..358e7e01 100644 --- a/YoutubeExplode/Bridge/SearchResponse.cs +++ b/YoutubeExplode/Bridge/SearchResponse.cs @@ -28,9 +28,15 @@ internal partial class SearchResponse(JsonElement content) [Lazy] public IReadOnlyList Playlists => ContentRoot + ?.EnumerateDescendantProperties("lockupViewModel") + .Select(j => new PlaylistData(j)) + .ToArray() + // fall back to older working paths + ?? ContentRoot ?.EnumerateDescendantProperties("playlistRenderer") .Select(j => new PlaylistData(j)) - .ToArray() ?? []; + .ToArray() + ?? []; [Lazy] public IReadOnlyList Channels => @@ -129,11 +135,20 @@ internal partial class SearchResponse public class PlaylistData(JsonElement content) { [Lazy] - public string? Id => content.GetPropertyOrNull("playlistId")?.GetStringOrNull(); + public string? Id => + content.GetPropertyOrNull("contentId")?.GetStringOrNull() + // fall back to older working paths + ?? content.GetPropertyOrNull("playlistId")?.GetStringOrNull(); + + [Lazy] + private JsonElement? Metadata => + content.GetPropertyOrNull("metadata")?.GetPropertyOrNull("lockupMetadataViewModel"); [Lazy] public string? Title => - content.GetPropertyOrNull("title")?.GetPropertyOrNull("simpleText")?.GetStringOrNull() + Metadata?.GetPropertyOrNull("title")?.GetPropertyOrNull("content")?.GetStringOrNull() + // fall back to older working paths + ?? content.GetPropertyOrNull("title")?.GetPropertyOrNull("simpleText")?.GetStringOrNull() ?? content .GetPropertyOrNull("title") ?.GetPropertyOrNull("runs") @@ -144,18 +159,38 @@ public class PlaylistData(JsonElement content) [Lazy] private JsonElement? AuthorDetails => - content + Metadata + ?.EnumerateDescendantProperties("metadataParts") + ?.ElementAtOrNull(0) + ?.EnumerateArrayOrNull() + ?.ElementAtOrNull(0) + ?.GetPropertyOrNull("text") + // fall back to older working paths + ?? content .GetPropertyOrNull("longBylineText") ?.GetPropertyOrNull("runs") ?.EnumerateArrayOrNull() ?.ElementAtOrNull(0); [Lazy] - public string? Author => AuthorDetails?.GetPropertyOrNull("text")?.GetStringOrNull(); + public string? Author => + AuthorDetails?.GetPropertyOrNull("content")?.GetStringOrNull() + // fall back to older working paths + ?? AuthorDetails?.GetPropertyOrNull("text")?.GetStringOrNull(); [Lazy] public string? ChannelId => AuthorDetails + ?.GetPropertyOrNull("commandRuns") + ?.EnumerateArrayOrNull() + ?.ElementAtOrNull(0) + ?.GetPropertyOrNull("onTap") + ?.GetPropertyOrNull("innertubeCommand") + ?.GetPropertyOrNull("browseEndpoint") + ?.GetPropertyOrNull("browseId") + ?.GetStringOrNull() + // fall back to older working paths + ?? AuthorDetails ?.GetPropertyOrNull("navigationEndpoint") ?.GetPropertyOrNull("browseEndpoint") ?.GetPropertyOrNull("browseId") @@ -164,11 +199,23 @@ public class PlaylistData(JsonElement content) [Lazy] public IReadOnlyList Thumbnails => content + .GetPropertyOrNull("contentImage") + ?.GetPropertyOrNull("collectionThumbnailViewModel") + ?.GetPropertyOrNull("primaryThumbnail") + ?.GetPropertyOrNull("thumbnailViewModel") + ?.GetPropertyOrNull("image") + ?.GetPropertyOrNull("sources") + ?.EnumerateArrayOrEmpty() + .Select(j => new ThumbnailData(j)) + .ToArray() + // fall back to older working paths + ?? content .GetPropertyOrNull("thumbnails") ?.EnumerateDescendantProperties("thumbnails") .SelectMany(j => j.EnumerateArrayOrEmpty()) .Select(j => new ThumbnailData(j)) - .ToArray() ?? []; + .ToArray() + ?? []; } }