diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/Creator.java b/extractor/src/main/java/org/schabi/newpipe/extractor/Creator.java new file mode 100644 index 0000000000..597321863d --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/Creator.java @@ -0,0 +1,110 @@ +package org.schabi.newpipe.extractor; + +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Class representing a creator of a piece of media that has been extracted. + */ +public final class Creator { + + /** + * Constant representing that the amount of subscribers of a {@link Creator} is unknown. + */ + public static final long UNKNOWN_SUBSCRIBER_COUNT = -1; + + @Nonnull + private final String name; + @Nonnull + private final String url; + @Nonnull + private final List avatars; + private final long subscriberCount; + private final boolean isVerified; + + /** + * Construct an {@link Creator} instance. + * + * @param name the name of the creator, which should be not null or empty + * @param url the URL to the creator's page, which should be not null + * or empty + * @param avatars the avatar of the creator, possibly in multiple resolutions + * @param subscriberCount the amount of subscribers/followers of the creator + * @param isVerified whether the creator has been verified by the platform + */ + public Creator(@Nonnull final String name, + @Nonnull final String url, + @Nonnull final List avatars, + final long subscriberCount, + final boolean isVerified) { + this.name = name; + this.url = url; + this.avatars = avatars; + this.subscriberCount = subscriberCount; + this.isVerified = isVerified; + } + + /** + * Get the name of the {@link Creator}. + * + * @return the {@link Creator}'s name. + */ + @Nonnull + public String getName() { + return name; + } + + /** + * Get the URL of the {@link Creator}. + * + * @return the {@link Creator}'s URL. + */ + @Nonnull + public String getUrl() { + return url; + } + + /** + * Get the avatars of the {@link Creator}. + * + * @return the {@link Creator}'s avatars. + */ + @Nonnull + public List getAvatars() { + return avatars; + } + + /** + * Get the amount of subscribers of this {@link Image}. + * + *

+ * If it is unknown, {@link #UNKNOWN_SUBSCRIBER_COUNT} is returned instead. + *

+ * + * @return the {@link Creator}'s amount of subscribers or {@link #UNKNOWN_SUBSCRIBER_COUNT} + */ + public long getSubscriberCount() { + return subscriberCount; + } + + /** + * Get whether the {@link Creator} has been verified by the platform. + * + * @return whether the {@link Creator} has been verified by the platform + */ + public boolean isVerified() { + return isVerified; + } + + /** + * Get a string representation of this {@link Creator} instance. + * + * @return a string representation of this {@link Creator} instance + */ + @Nonnull + @Override + public String toString() { + return "Creator {" + "name=" + name + ", url=" + url + ", avatars=" + avatars + + ", subscriberCount=" + subscriberCount + ", isVerified=" + isVerified + "}"; + } +} 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 b54441db5a..48357b4597 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 @@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.services.youtube; +import static org.schabi.newpipe.extractor.Creator.UNKNOWN_SUBSCRIBER_COUNT; import static org.schabi.newpipe.extractor.NewPipe.getDownloader; import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.ANDROID_CLIENT_VERSION; import static org.schabi.newpipe.extractor.services.youtube.ClientsConstants.DESKTOP_CLIENT_PLATFORM; @@ -46,6 +47,7 @@ import com.grack.nanojson.JsonWriter; import org.jsoup.nodes.Entities; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.Image.ResolutionLevel; import org.schabi.newpipe.extractor.downloader.Response; @@ -1608,4 +1610,52 @@ public static JsonObject getFirstCollaborator(final JsonObject navigationEndpoin return null; } } + + /** + * Gets the first collaborator, which is the channel that owns the video, + * i.e. the video is displayed on their channel page. + * + * @param navigationEndpoint JSON object for the navigationEndpoint + * @return The first collaborator in the JSON object or {@code null} + */ + @Nullable + public static List getCollaborators(final JsonObject navigationEndpoint) + throws ParsingException { + // CHECKSTYLE:OFF + final JsonArray listItems = JsonUtils.getArray(navigationEndpoint, "showDialogCommand.panelLoadingStrategy.inlineContent.dialogViewModel.customContent.listViewModel.listItems"); + // CHECKSTYLE:ON + + return listItems + .streamAsJsonObjects() + .map(item -> { + final JsonObject channel = item.getObject("listItemViewModel"); + + final String url = getUrlFromNavigationEndpoint( + channel.getObject("rendererContext") + .getObject("commandContext") + .getObject("onTap") + .getObject("innertubeCommand")); + final List avatars = getImagesFromThumbnailsArray( + channel.getObject("leadingAccessory") + .getObject("avatarViewModel") + .getObject("image") + .getArray("sources")); + + long subscriberCount = UNKNOWN_SUBSCRIBER_COUNT; + try { + final String content = channel.getObject("subtitle").getString("content"); + subscriberCount = Utils.mixedNumberWordToLong(content.split("•")[1]); + } catch (final NumberFormatException | ParsingException e) { } + + return new Creator( + channel.getObject("title").getString("content"), + url, + avatars, + subscriberCount, + YoutubeParsingHelper.hasArtistOrVerifiedIconBadgeAttachment( + channel.getObject("title").getArray("attachmentRuns")) + ); + }) + .collect(Collectors.toList()); + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index ba23eb6463..5f207a1288 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -39,6 +39,7 @@ import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonWriter; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.MetaInfo; @@ -1684,6 +1685,21 @@ public List getMetaInfo() throws ParsingException { .getArray("contents")); } + @Nonnull + @Override + public List getCreators() throws ParsingException { + final JsonObject navigationEndpoint = JsonUtils.getObject(getVideoSecondaryInfoRenderer(), + "owner.videoOwnerRenderer.navigationEndpoint"); + + if (!navigationEndpoint.has("showDialogCommand")) { + // video has only one creator + return List.of(new Creator(getUploaderName(), getUploaderUrl(), + getUploaderAvatars(), getUploaderSubscriberCount(), isUploaderVerified())); + } + + return YoutubeParsingHelper.getCollaborators(navigationEndpoint); + } + /** * Set the {@link PoTokenProvider} instance to be used for fetching {@code poToken}s. * diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java index 7b4deaaa58..211da1735a 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamInfoItemExtractor.java @@ -18,6 +18,7 @@ package org.schabi.newpipe.extractor.services.youtube.extractors; +import static org.schabi.newpipe.extractor.Creator.UNKNOWN_SUBSCRIBER_COUNT; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getThumbnailsFromInfoItem; import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getImagesFromThumbnailsArray; @@ -27,6 +28,7 @@ import com.grack.nanojson.JsonArray; import com.grack.nanojson.JsonObject; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.localization.DateWrapper; @@ -502,4 +504,18 @@ public ContentAvailability getContentAvailability() throws ParsingException { return ContentAvailability.AVAILABLE; } + @Nonnull + @Override + public List getCreators() throws ParsingException { + final JsonObject navigationEndpoint = videoInfo.getObject("shortBylineText") + .getArray("runs").getObject(0).getObject("navigationEndpoint"); + + if (!navigationEndpoint.has("showDialogCommand")) { + // video has only one creator + return List.of(new Creator(getUploaderName(), getUploaderUrl(), + getUploaderAvatars(), UNKNOWN_SUBSCRIBER_COUNT, isUploaderVerified())); + } + + return YoutubeParsingHelper.getCollaborators(navigationEndpoint); + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java index 63650a7906..8747429881 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java @@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.stream; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItemsCollector; @@ -593,6 +594,16 @@ public ContentAvailability getContentAvailability() throws ParsingException { return ContentAvailability.UNKNOWN; } + /** + * Gets the creators of the stream. + * + * @return The creators of the stream. + */ + @Nonnull + public List getCreators() throws ParsingException { + return List.of(); + } + public enum Privacy { PUBLIC, UNLISTED, diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java index 62fb6bbf74..154d89216e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java @@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.stream; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.Info; import org.schabi.newpipe.extractor.InfoItem; @@ -335,6 +336,11 @@ private static void extractOptionalData(final StreamInfo streamInfo, } catch (final Exception e) { streamInfo.addError(e); } + try { + streamInfo.setCreators(extractor.getCreators()); + } catch (final Exception e) { + streamInfo.addError(e); + } streamInfo.setRelatedItems(ExtractorHelper.getRelatedItemsOrLogError(streamInfo, extractor)); @@ -388,6 +394,7 @@ private static void extractOptionalData(final StreamInfo streamInfo, private boolean shortFormContent = false; @Nonnull private ContentAvailability contentAvailability = ContentAvailability.AVAILABLE; + private List creators = List.of(); /** * Preview frames, e.g. for the storyboard / seekbar thumbnail preview @@ -743,4 +750,13 @@ public ContentAvailability getContentAvailability() { public void setContentAvailability(@Nonnull final ContentAvailability availability) { this.contentAvailability = availability; } + + @Nonnull + public List getCreators() { + return creators; + } + + public void setCreators(@Nonnull final List creators) { + this.creators = creators; + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItem.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItem.java index fdccedfa65..f77211921c 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItem.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItem.java @@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.stream; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.localization.DateWrapper; @@ -49,6 +50,8 @@ public class StreamInfoItem extends InfoItem { private boolean shortFormContent = false; @Nonnull private ContentAvailability contentAvailability = ContentAvailability.AVAILABLE; + @Nonnull + private List creators = List.of(); public StreamInfoItem(final int serviceId, final String url, @@ -162,6 +165,23 @@ public void setContentAvailability(@Nonnull final ContentAvailability availabili this.contentAvailability = availability; } + /** + * Gets the creators of the stream. + * + * @return The creators of the stream. + */ + @Nonnull + public List getCreators() { + return creators; + } + + /** + * Sets the creators of the stream. + */ + public void setCreators(@Nonnull final List creators) { + this.creators = creators; + } + @Override public String toString() { return "StreamInfoItem{" diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.java index fb56e93b99..62ad54dc5e 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemExtractor.java @@ -20,6 +20,7 @@ package org.schabi.newpipe.extractor.stream; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.InfoItemExtractor; import org.schabi.newpipe.extractor.exceptions.ParsingException; @@ -162,4 +163,16 @@ default boolean isShortFormContent() throws ParsingException { default ContentAvailability getContentAvailability() throws ParsingException { return ContentAvailability.UNKNOWN; } + + + /** + * Get the creators/collaborators of the stream. + * + * @return The stream's creators + * @throws ParsingException if there is an error in the extraction + */ + @Nonnull + default List getCreators() throws ParsingException { + return List.of(); + } } diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemsCollector.java b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemsCollector.java index a0fe3a6948..89ce69247d 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemsCollector.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfoItemsCollector.java @@ -108,6 +108,11 @@ public StreamInfoItem extract(final StreamInfoItemExtractor extractor) throws Pa } catch (final Exception e) { addError(e); } + try { + resultItem.setCreators(extractor.getCreators()); + } catch (final Exception e) { + addError(e); + } return resultItem; } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemTest.java index 0782bbd56b..d603581915 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.schabi.newpipe.downloader.DownloaderFactory.getMockPath; +import static org.schabi.newpipe.extractor.ExtractorAsserts.assertNotEmpty; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; @@ -80,4 +81,26 @@ void lockupViewModelPremiere() () -> assertFalse(extractor.isShortFormContent()) ); } + + @Test + void collaborators() + throws FileNotFoundException, JsonParserException { + final var json = JsonParser.object().from(new FileInputStream(getMockPath( + YoutubeStreamInfoItemTest.class, "collaborators") + ".json")); + final var timeAgoParser = TimeAgoPatternsManager.getTimeAgoParserFor(Localization.DEFAULT); + final var extractor = new YoutubeStreamInfoItemExtractor(json, timeAgoParser); + assertAll( + () -> assertEquals(StreamType.VIDEO_STREAM, extractor.getStreamType()), + () -> assertEquals("https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw", extractor.getUploaderUrl()), + () -> assertNotEmpty(extractor.getCreators()), + () -> assertEquals("https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw", extractor.getCreators().get(0).getUrl()), + () -> assertEquals("The Cherno", extractor.getCreators().get(0).getName()), + () -> assertEquals(731_000, extractor.getCreators().get(0).getSubscriberCount()), + () -> assertTrue( extractor.getCreators().get(0).isVerified()), + () -> assertEquals("https://www.youtube.com/channel/UCQvW_89l7f-hCMP1pzGm4xw", extractor.getCreators().get(1).getUrl()), + () -> assertEquals("Nathan Baggs", extractor.getCreators().get(1).getName()), + () -> assertEquals(95_900, extractor.getCreators().get(1).getSubscriberCount()), + () -> assertFalse( extractor.getCreators().get(1).isVerified()) + ); + } } diff --git a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorCollaboratorsTest.java b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorCollaboratorsTest.java index 91ad41ba2d..d52080f21c 100644 --- a/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorCollaboratorsTest.java +++ b/extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/stream/YoutubeStreamExtractorCollaboratorsTest.java @@ -5,6 +5,8 @@ import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestImageCollection; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.schabi.newpipe.extractor.Creator; import org.schabi.newpipe.extractor.Image; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest; @@ -63,4 +65,11 @@ public void testUploaderAvatars() throws Exception { assertNotEmpty(avatars); defaultTestImageCollection(avatars); } + + @Test + public void testColloborators() throws Exception { + List creators = extractor().getCreators(); + assertNotEmpty(creators); + } + } diff --git a/extractor/src/test/resources/mocks/v1/org/schabi/newpipe/extractor/services/youtube/youtubestreaminfoitem/collaborators.json b/extractor/src/test/resources/mocks/v1/org/schabi/newpipe/extractor/services/youtube/youtubestreaminfoitem/collaborators.json new file mode 100644 index 0000000000..bc25438076 --- /dev/null +++ b/extractor/src/test/resources/mocks/v1/org/schabi/newpipe/extractor/services/youtube/youtubestreaminfoitem/collaborators.json @@ -0,0 +1,1214 @@ +{ + "videoId": "Glq1oDBy1cQ", + "thumbnail": { + "thumbnails": [ + { + "url": "https://i.ytimg.com/vi/Glq1oDBy1cQ/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDtq6xA6h9zlczYrqf-5EZruTr-SA", + "width": 168, + "height": 94 + }, + { + "url": "https://i.ytimg.com/vi/Glq1oDBy1cQ/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDMl9kE2tsNTPs7ilUiM7FgNhwIow", + "width": 196, + "height": 110 + }, + { + "url": "https://i.ytimg.com/vi/Glq1oDBy1cQ/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCXR0cJ_43LyTNVTWOwOkRJ6CFw1A", + "width": 246, + "height": 138 + }, + { + "url": "https://i.ytimg.com/vi/Glq1oDBy1cQ/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBy-Icr7HOsD9CP8VOGEUshkErgGw", + "width": 336, + "height": 188 + } + ] + }, + "title": { + "runs": [ + { + "text": "SOMEONE Code Reviewed Hazel, My Game Engine" + } + ], + "accessibility": { + "accessibilityData": { + "label": "SOMEONE Code Reviewed Hazel, My Game Engine 1 hour, 12 minutes" + } + } + }, + "descriptionSnippet": { + "runs": [ + { + "text": "Check out the NEW CodeRabbit CLI for FREE! ► https://coderabbit.link/cherno-cli\n\nPatreon ► https://patreon.com/thecherno\nInstagram ► https://instagram.com/thecherno\nTwitter ► https://twitte..." + } + ] + }, + "longBylineText": { + "runs": [ + { + "text": "The Cherno and Nathan Baggs", + "navigationEndpoint": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "interactionLoggingCommandMetadata": { + "screenVisualElement": { + "uiType": 269990 + } + } + }, + "showDialogCommand": { + "panelLoadingStrategy": { + "inlineContent": { + "dialogViewModel": { + "header": { + "dialogHeaderViewModel": { + "headline": { + "content": "Collaborators" + } + } + }, + "customContent": { + "listViewModel": { + "listItems": [ + { + "listItemViewModel": { + "title": { + "content": "The Cherno", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + }, + { + "startIndex": 10, + "styleRunExtensions": { + "styleRunColorMapExtension": { + "colorMap": [ + { + "key": "USER_INTERFACE_THEME_LIGHT", + "value": 4284506208 + }, + { + "key": "USER_INTERFACE_THEME_DARK", + "value": 4289374890 + } + ] + } + } + } + ], + "attachmentRuns": [ + { + "startIndex": 10, + "length": 0, + "element": { + "type": { + "imageType": { + "image": { + "sources": [ + { + "clientResource": { + "imageName": "CHECK_CIRCLE_FILLED" + }, + "width": 14, + "height": 14 + } + ] + } + } + }, + "properties": { + "layoutProperties": { + "height": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "width": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "margin": { + "left": { + "value": 4, + "unit": "DIMENSION_UNIT_POINT" + } + } + } + } + }, + "alignment": "ALIGNMENT_VERTICAL_CENTER" + } + ] + }, + "subtitle": { + "content": "‎⁨@TheCherno⁩ • ⁨731K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/EmbIHnpmF1J0LgyUbCMK7QmfDZZm7u_GQd5eVx4XG06wIvgbagCY6WYpf2fvSdPoL1LMLkw8Iw=s68-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "The Cherno. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "The Cherno - 731K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQ-W1KE9EYfdxhL6S4twUNw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQ-W1KE9EYfdxhL6S4twUNw" + } + } + } + } + } + } + }, + { + "listItemViewModel": { + "title": { + "content": "Nathan Baggs", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + } + ] + }, + "subtitle": { + "content": "‎⁨@nathanbaggs⁩ • ⁨95.9K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/_M5TrSBzMXBCAzrH7yg5_K5lwBL6llto5YR-CuFQIPPe-bQYIRcimQvkz0C605TDUUbuK1W_=s88-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "Nathan Baggs. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "Nathan Baggs - 95.9K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQvW_89l7f-hCMP1pzGm4xw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQvW_89l7f-hCMP1pzGm4xw" + } + } + } + } + } + } + } + ] + } + } + } + }, + "screenVe": 269990 + } + } + } + } + ] + }, + "publishedTimeText": { + "simpleText": "10 hours ago" + }, + "lengthText": { + "accessibility": { + "accessibilityData": { + "label": "1 hour, 12 minutes, 27 seconds" + } + }, + "simpleText": "1:12:27" + }, + "viewCountText": { + "simpleText": "18,020 views" + }, + "navigationEndpoint": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJWhhVQ1EtVzFLRTlFWWZkeGhMNlM0dHdVTneaAQMQ8jjKAQShg-Po", + "commandMetadata": { + "webCommandMetadata": { + "url": "/watch?v=Glq1oDBy1cQ", + "webPageType": "WEB_PAGE_TYPE_WATCH", + "rootVe": 3832 + } + }, + "watchEndpoint": { + "videoId": "Glq1oDBy1cQ", + "params": "igMCCAE%3D", + "watchEndpointSupportedOnesieConfig": { + "html5PlaybackOnesieConfig": { + "commonConfig": { + "url": "https://rr6---sn-uxax4vopj5qx-q0n6.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&ofpcc=1&msp=1&odepv=1&id=1a5ab5a03072d5c4&ip=2a02%3A3100%3A412f%3Ae600%3Ae6b6%3Adf7%3Ad95a%3A866d&initcwndbps=1608750&mt=1762286067&oweuc=&pxtags=Cg4KAnR4Egg1MTUzOTg1NA&rxtags=Cg4KAnR4Egg1MTUzOTg1Mw%2CCg4KAnR4Egg1MTUzOTg1NA%2CCg4KAnR4Egg1MTUzOTg1NQ" + } + } + } + } + }, + "ownerText": { + "runs": [ + { + "text": "The Cherno and Nathan Baggs", + "navigationEndpoint": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "interactionLoggingCommandMetadata": { + "screenVisualElement": { + "uiType": 269990 + } + } + }, + "showDialogCommand": { + "panelLoadingStrategy": { + "inlineContent": { + "dialogViewModel": { + "header": { + "dialogHeaderViewModel": { + "headline": { + "content": "Collaborators" + } + } + }, + "customContent": { + "listViewModel": { + "listItems": [ + { + "listItemViewModel": { + "title": { + "content": "The Cherno", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + }, + { + "startIndex": 10, + "styleRunExtensions": { + "styleRunColorMapExtension": { + "colorMap": [ + { + "key": "USER_INTERFACE_THEME_LIGHT", + "value": 4284506208 + }, + { + "key": "USER_INTERFACE_THEME_DARK", + "value": 4289374890 + } + ] + } + } + } + ], + "attachmentRuns": [ + { + "startIndex": 10, + "length": 0, + "element": { + "type": { + "imageType": { + "image": { + "sources": [ + { + "clientResource": { + "imageName": "CHECK_CIRCLE_FILLED" + }, + "width": 14, + "height": 14 + } + ] + } + } + }, + "properties": { + "layoutProperties": { + "height": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "width": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "margin": { + "left": { + "value": 4, + "unit": "DIMENSION_UNIT_POINT" + } + } + } + } + }, + "alignment": "ALIGNMENT_VERTICAL_CENTER" + } + ] + }, + "subtitle": { + "content": "‎⁨@TheCherno⁩ • ⁨731K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/EmbIHnpmF1J0LgyUbCMK7QmfDZZm7u_GQd5eVx4XG06wIvgbagCY6WYpf2fvSdPoL1LMLkw8Iw=s68-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "The Cherno. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "The Cherno - 731K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQ-W1KE9EYfdxhL6S4twUNw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQ-W1KE9EYfdxhL6S4twUNw" + } + } + } + } + } + } + }, + { + "listItemViewModel": { + "title": { + "content": "Nathan Baggs", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + } + ] + }, + "subtitle": { + "content": "‎⁨@nathanbaggs⁩ • ⁨95.9K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/_M5TrSBzMXBCAzrH7yg5_K5lwBL6llto5YR-CuFQIPPe-bQYIRcimQvkz0C605TDUUbuK1W_=s88-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "Nathan Baggs. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "Nathan Baggs - 95.9K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQvW_89l7f-hCMP1pzGm4xw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQvW_89l7f-hCMP1pzGm4xw" + } + } + } + } + } + } + } + ] + } + } + } + }, + "screenVe": 269990 + } + } + } + } + ] + }, + "shortBylineText": { + "runs": [ + { + "text": "The Cherno and Nathan Baggs", + "navigationEndpoint": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "interactionLoggingCommandMetadata": { + "screenVisualElement": { + "uiType": 269990 + } + } + }, + "showDialogCommand": { + "panelLoadingStrategy": { + "inlineContent": { + "dialogViewModel": { + "header": { + "dialogHeaderViewModel": { + "headline": { + "content": "Collaborators" + } + } + }, + "customContent": { + "listViewModel": { + "listItems": [ + { + "listItemViewModel": { + "title": { + "content": "The Cherno", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + }, + { + "startIndex": 10, + "styleRunExtensions": { + "styleRunColorMapExtension": { + "colorMap": [ + { + "key": "USER_INTERFACE_THEME_LIGHT", + "value": 4284506208 + }, + { + "key": "USER_INTERFACE_THEME_DARK", + "value": 4289374890 + } + ] + } + } + } + ], + "attachmentRuns": [ + { + "startIndex": 10, + "length": 0, + "element": { + "type": { + "imageType": { + "image": { + "sources": [ + { + "clientResource": { + "imageName": "CHECK_CIRCLE_FILLED" + }, + "width": 14, + "height": 14 + } + ] + } + } + }, + "properties": { + "layoutProperties": { + "height": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "width": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "margin": { + "left": { + "value": 4, + "unit": "DIMENSION_UNIT_POINT" + } + } + } + } + }, + "alignment": "ALIGNMENT_VERTICAL_CENTER" + } + ] + }, + "subtitle": { + "content": "‎⁨@TheCherno⁩ • ⁨731K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/EmbIHnpmF1J0LgyUbCMK7QmfDZZm7u_GQd5eVx4XG06wIvgbagCY6WYpf2fvSdPoL1LMLkw8Iw=s68-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "The Cherno. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "The Cherno - 731K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQ-W1KE9EYfdxhL6S4twUNw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQ-W1KE9EYfdxhL6S4twUNw" + } + } + } + } + } + } + }, + { + "listItemViewModel": { + "title": { + "content": "Nathan Baggs", + "styleRuns": [ + { + "fontColor": 4294967295 + }, + { + "weightLabel": "FONT_WEIGHT_BOLD" + } + ] + }, + "subtitle": { + "content": "‎⁨@nathanbaggs⁩ • ⁨95.9K subscribers⁩" + }, + "trailingImage": { + "sources": [ + { + "clientResource": { + "imageName": "yt-sys-icons:chevron_right" + } + } + ] + }, + "leadingAccessory": { + "avatarViewModel": { + "image": { + "sources": [ + { + "url": "https://yt3.googleusercontent.com/_M5TrSBzMXBCAzrH7yg5_K5lwBL6llto5YR-CuFQIPPe-bQYIRcimQvkz0C605TDUUbuK1W_=s88-c-k-c0x00ffffff-no-rj" + } + ], + "processor": { + "borderImageProcessor": { + "circular": true + } + } + }, + "accessibilityText": "Nathan Baggs. Go to channel.", + "avatarImageSize": "AVATAR_SIZE_M" + } + }, + "rendererContext": { + "accessibilityContext": { + "label": "Nathan Baggs - 95.9K subscribers. Go to channel" + }, + "commandContext": { + "onTap": { + "innertubeCommand": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/channel/UCQvW_89l7f-hCMP1pzGm4xw", + "webPageType": "WEB_PAGE_TYPE_CHANNEL", + "rootVe": 3611, + "apiUrl": "/youtubei/v1/browse" + } + }, + "browseEndpoint": { + "browseId": "UCQvW_89l7f-hCMP1pzGm4xw" + } + } + } + } + } + } + } + ] + } + } + } + }, + "screenVe": 269990 + } + } + } + } + ] + }, + "trackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJQMSry4ODtK2tGg==", + "showActionMenu": false, + "shortViewCountText": { + "accessibility": { + "accessibilityData": { + "label": "18 thousand views" + } + }, + "simpleText": "18K views" + }, + "menu": { + "menuRenderer": { + "items": [ + { + "menuServiceItemRenderer": { + "text": { + "runs": [ + { + "text": "Add to queue" + } + ] + }, + "icon": { + "iconType": "ADD_TO_QUEUE_TAIL" + }, + "serviceEndpoint": { + "clickTrackingParams": "CJwCEP6YBBgKIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true + } + }, + "signalServiceEndpoint": { + "signal": "CLIENT_SIGNAL", + "actions": [ + { + "clickTrackingParams": "CJwCEP6YBBgKIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "addToPlaylistCommand": { + "openMiniplayer": true, + "videoId": "Glq1oDBy1cQ", + "listType": "PLAYLIST_EDIT_LIST_TYPE_QUEUE", + "onCreateListCommand": { + "clickTrackingParams": "CJwCEP6YBBgKIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true, + "apiUrl": "/youtubei/v1/playlist/create" + } + }, + "createPlaylistServiceEndpoint": { + "videoIds": [ + "Glq1oDBy1cQ" + ], + "params": "CAQ%3D" + } + }, + "videoIds": [ + "Glq1oDBy1cQ" + ], + "videoCommand": { + "clickTrackingParams": "CJwCEP6YBBgKIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "/watch?v=Glq1oDBy1cQ", + "webPageType": "WEB_PAGE_TYPE_WATCH", + "rootVe": 3832 + } + }, + "watchEndpoint": { + "videoId": "Glq1oDBy1cQ", + "watchEndpointSupportedOnesieConfig": { + "html5PlaybackOnesieConfig": { + "commonConfig": { + "url": "https://rr6---sn-uxax4vopj5qx-q0n6.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&ofpcc=1&msp=1&odepv=1&id=1a5ab5a03072d5c4&ip=2a02%3A3100%3A412f%3Ae600%3Ae6b6%3Adf7%3Ad95a%3A866d&initcwndbps=1608750&mt=1762286067&oweuc=&pxtags=Cg4KAnR4Egg1MTUzOTg1NA&rxtags=Cg4KAnR4Egg1MTUzOTg1Mw%2CCg4KAnR4Egg1MTUzOTg1NA%2CCg4KAnR4Egg1MTUzOTg1NQ" + } + } + } + } + } + } + } + ] + } + }, + "trackingParams": "CJwCEP6YBBgKIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + }, + { + "menuNavigationItemRenderer": { + "text": { + "runs": [ + { + "text": "Save to playlist" + } + ] + }, + "icon": { + "iconType": "BOOKMARK_BORDER" + }, + "navigationEndpoint": { + "clickTrackingParams": "CJsCEJSsCRgLIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "url": "https://accounts.google.com/ServiceLogin?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Ddesktop%26hl%3Den&hl=en", + "webPageType": "WEB_PAGE_TYPE_UNKNOWN", + "rootVe": 83769 + } + }, + "signInEndpoint": { + "nextEndpoint": { + "clickTrackingParams": "CJsCEJSsCRgLIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "showSheetCommand": { + "panelLoadingStrategy": { + "requestTemplate": { + "panelId": "PAadd_to_playlist", + "params": "-gYNCgtHbHExb0RCeTFjUQ%3D%3D" + } + } + } + } + } + }, + "trackingParams": "CJsCEJSsCRgLIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + }, + { + "menuServiceItemDownloadRenderer": { + "serviceEndpoint": { + "clickTrackingParams": "CJoCENGqBRgMIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "offlineVideoEndpoint": { + "videoId": "Glq1oDBy1cQ", + "onAddCommand": { + "clickTrackingParams": "CJoCENGqBRgMIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "getDownloadActionCommand": { + "videoId": "Glq1oDBy1cQ", + "params": "CAIQAA%3D%3D", + "isCrossDeviceDownload": false + } + } + } + }, + "trackingParams": "CJoCENGqBRgMIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + }, + { + "menuServiceItemRenderer": { + "text": { + "runs": [ + { + "text": "Share" + } + ] + }, + "icon": { + "iconType": "SHARE" + }, + "serviceEndpoint": { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true, + "apiUrl": "/youtubei/v1/share/get_share_panel" + } + }, + "shareEntityServiceEndpoint": { + "serializedShareEntity": "CgtHbHExb0RCeTFjUQ%3D%3D", + "commands": [ + { + "clickTrackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "openPopupAction": { + "popup": { + "unifiedSharePanelRenderer": { + "trackingParams": "CJkCEI5iIhMIspGl96TZkAMV6GZ6BR1ziSWJ", + "showLoadingSpinner": true + } + }, + "popupType": "DIALOG", + "beReused": true + } + } + ] + } + }, + "trackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + } + ], + "trackingParams": "CJYCENwwIhMIspGl96TZkAMV6GZ6BR1ziSWJ", + "accessibility": { + "accessibilityData": { + "label": "Action menu" + } + } + } + }, + "thumbnailOverlays": [ + { + "thumbnailOverlayTimeStatusRenderer": { + "text": { + "accessibility": { + "accessibilityData": { + "label": "1 hour, 12 minutes, 27 seconds" + } + }, + "simpleText": "1:12:27" + }, + "style": "DEFAULT" + } + }, + { + "thumbnailOverlayToggleButtonRenderer": { + "isToggled": false, + "untoggledIcon": { + "iconType": "WATCH_LATER" + }, + "toggledIcon": { + "iconType": "CHECK" + }, + "untoggledTooltip": "Watch later", + "toggledTooltip": "Added", + "untoggledServiceEndpoint": { + "clickTrackingParams": "CJgCEPnnAxgBIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true, + "apiUrl": "/youtubei/v1/browse/edit_playlist" + } + }, + "playlistEditEndpoint": { + "playlistId": "WL", + "actions": [ + { + "addedVideoId": "Glq1oDBy1cQ", + "action": "ACTION_ADD_VIDEO" + } + ] + } + }, + "toggledServiceEndpoint": { + "clickTrackingParams": "CJgCEPnnAxgBIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true, + "apiUrl": "/youtubei/v1/browse/edit_playlist" + } + }, + "playlistEditEndpoint": { + "playlistId": "WL", + "actions": [ + { + "action": "ACTION_REMOVE_VIDEO_BY_VIDEO_ID", + "removedVideoId": "Glq1oDBy1cQ" + } + ] + } + }, + "untoggledAccessibility": { + "accessibilityData": { + "label": "Watch later" + } + }, + "toggledAccessibility": { + "accessibilityData": { + "label": "Added" + } + }, + "trackingParams": "CJgCEPnnAxgBIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + }, + { + "thumbnailOverlayToggleButtonRenderer": { + "untoggledIcon": { + "iconType": "ADD_TO_QUEUE_TAIL" + }, + "toggledIcon": { + "iconType": "PLAYLIST_ADD_CHECK" + }, + "untoggledTooltip": "Add to queue", + "toggledTooltip": "Added", + "untoggledServiceEndpoint": { + "clickTrackingParams": "CJcCEMfsBBgCIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true + } + }, + "signalServiceEndpoint": { + "signal": "CLIENT_SIGNAL", + "actions": [ + { + "clickTrackingParams": "CJcCEMfsBBgCIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "addToPlaylistCommand": { + "openMiniplayer": true, + "videoId": "Glq1oDBy1cQ", + "listType": "PLAYLIST_EDIT_LIST_TYPE_QUEUE", + "onCreateListCommand": { + "clickTrackingParams": "CJcCEMfsBBgCIhMIspGl96TZkAMV6GZ6BR1ziSWJygEEoYPj6A==", + "commandMetadata": { + "webCommandMetadata": { + "sendPost": true, + "apiUrl": "/youtubei/v1/playlist/create" + } + }, + "createPlaylistServiceEndpoint": { + "videoIds": [ + "Glq1oDBy1cQ" + ], + "params": "CAQ%3D" + } + }, + "videoIds": [ + "Glq1oDBy1cQ" + ] + } + } + ] + } + }, + "untoggledAccessibility": { + "accessibilityData": { + "label": "Add to queue" + } + }, + "toggledAccessibility": { + "accessibilityData": { + "label": "Added" + } + }, + "trackingParams": "CJcCEMfsBBgCIhMIspGl96TZkAMV6GZ6BR1ziSWJ" + } + }, + { + "thumbnailOverlayNowPlayingRenderer": { + "text": { + "runs": [ + { + "text": "Now playing" + } + ] + } + } + } + ], + "richThumbnail": { + "movingThumbnailRenderer": { + "movingThumbnailDetails": { + "thumbnails": [ + { + "url": "https://i.ytimg.com/an_webp/Glq1oDBy1cQ/mqdefault_6s.webp?du=3000&sqp=COiKqcgG&rs=AOn4CLDdjeiiI1x7nhHI7hSlnqPxgZCMZQ", + "width": 320, + "height": 180 + } + ], + "logAsMovingThumbnail": true + }, + "enableHoveredLogging": true, + "enableOverlay": true + } + }, + "attributedBylineText": { + "textViewModel": { + "text": { + "content": "The Cherno and Nathan Baggs", + "styleRuns": [ + { + "startIndex": 0, + "length": 27 + }, + { + "startIndex": 10, + "length": 1, + "styleRunExtensions": { + "styleRunColorMapExtension": { + "colorMap": [ + { + "key": "USER_INTERFACE_THEME_LIGHT", + "value": 4284506208 + }, + { + "key": "USER_INTERFACE_THEME_DARK", + "value": 4289374890 + } + ] + } + } + } + ], + "attachmentRuns": [ + { + "startIndex": 10, + "element": { + "type": { + "imageType": { + "image": { + "sources": [ + { + "clientResource": { + "imageName": "CHECK_CIRCLE_FILLED" + }, + "width": 14, + "height": 14 + } + ] + } + } + }, + "properties": { + "layoutProperties": { + "height": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "width": { + "value": 14, + "unit": "DIMENSION_UNIT_POINT" + }, + "margin": { + "left": { + "value": 4, + "unit": "DIMENSION_UNIT_POINT" + } + } + } + } + }, + "alignment": "ALIGNMENT_VERTICAL_CENTER" + } + ] + } + } + } +}