From 7ebe01171188cc7b8051e0be7629139abad8e20a Mon Sep 17 00:00:00 2001 From: Eutalix Date: Fri, 3 Apr 2026 13:19:55 -0300 Subject: [PATCH 1/7] Add endscreen data parsing from YouTube API - Add EndScreenItem interface for public API contract - Add EndScreen, EndScreenRenderer, EndScreenElement models to parse JSON - Add YouTubeEndScreenItem implementation - Parse endscreen data in WatchNextResult - Expose endscreen items via MediaItemMetadata.getEndScreenItems() The YouTube API already returns endscreen data (interactive elements shown at the end of videos), but it was being ignored. This change adds the parsing layer to make the data available to clients. No UI implementation yet - this is just the data/parsing layer. --- .../data/EndScreenItem.java | 20 +++ .../data/MediaItemMetadata.java | 1 + .../youtubeapi/next/v1/models/EndScreen.java | 12 ++ .../next/v1/models/EndScreenElement.java | 118 ++++++++++++++++ .../next/v1/models/EndScreenRenderer.java | 22 +++ .../next/v1/result/WatchNextResult.java | 7 + .../service/data/YouTubeEndScreenItem.java | 127 ++++++++++++++++++ .../data/YouTubeMediaItemMetadata.java | 24 ++++ 8 files changed, 331 insertions(+) create mode 100644 mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/EndScreenItem.java create mode 100644 youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreen.java create mode 100644 youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java create mode 100644 youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenRenderer.java create mode 100644 youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java diff --git a/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/EndScreenItem.java b/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/EndScreenItem.java new file mode 100644 index 000000000..0f36face5 --- /dev/null +++ b/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/EndScreenItem.java @@ -0,0 +1,20 @@ +package com.liskovsoft.mediaserviceinterfaces.data; + +public interface EndScreenItem { + int TYPE_VIDEO = 0; + int TYPE_CHANNEL = 1; + int TYPE_PLAYLIST = 2; + int TYPE_UNKNOWN = 3; + + int getType(); + String getTitle(); + String getMetadata(); + String getImageUrl(); + String getId(); // videoId, channelId, or playlistId + long getStartTimeMs(); + long getEndTimeMs(); + float getLeft(); + float getTop(); + float getWidth(); + float getAspectRatio(); +} \ No newline at end of file diff --git a/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/MediaItemMetadata.java b/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/MediaItemMetadata.java index a63399083..d2fd9600e 100644 --- a/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/MediaItemMetadata.java +++ b/mediaserviceinterfaces/src/main/java/com/liskovsoft/mediaserviceinterfaces/data/MediaItemMetadata.java @@ -34,4 +34,5 @@ public interface MediaItemMetadata { List getNotificationStates(); long getDurationMs(); String getBadgeText(); + List getEndScreenItems(); } diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreen.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreen.java new file mode 100644 index 000000000..1e117fa85 --- /dev/null +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreen.java @@ -0,0 +1,12 @@ +package com.liskovsoft.youtubeapi.next.v1.models; + +import com.google.gson.annotations.SerializedName; + +public class EndScreen { + @SerializedName("endscreenRenderer") + private EndScreenRenderer mRenderer; + + public EndScreenRenderer getRenderer() { + return mRenderer; + } +} \ No newline at end of file diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java new file mode 100644 index 000000000..28907de8d --- /dev/null +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java @@ -0,0 +1,118 @@ +package com.liskovsoft.youtubeapi.next.v1.models; + +import com.google.gson.annotations.SerializedName; +import com.liskovsoft.googlecommon.common.models.V2.TextItem; +import com.liskovsoft.youtubeapi.common.models.gen.CommonItems; + +public class EndScreenElement { + @SerializedName("style") + private String mStyle; // "CHANNEL", "VIDEO", "PLAYLIST" + + @SerializedName("image") + private CommonItems.Thumbnail mImage; + + @SerializedName("title") + private TextItem mTitle; + + @SerializedName("metadata") + private TextItem mMetadata; + + @SerializedName("left") + private float mLeft; + + @SerializedName("top") + private float mTop; + + @SerializedName("width") + private float mWidth; + + @SerializedName("aspectRatio") + private float mAspectRatio; + + @SerializedName("startMs") + private String mStartMs; + + @SerializedName("endMs") + private String mEndMs; + + @SerializedName("endpoint") + private Endpoint mEndpoint; + + public String getStyle() { + return mStyle; + } + + public CommonItems.Thumbnail getImage() { + return mImage; + } + + public TextItem getTitle() { + return mTitle; + } + + public TextItem getMetadata() { + return mMetadata; + } + + public float getLeft() { + return mLeft; + } + + public float getTop() { + return mTop; + } + + public float getWidth() { + return mWidth; + } + + public float getAspectRatio() { + return mAspectRatio; + } + + public String getStartMs() { + return mStartMs; + } + + public String getEndMs() { + return mEndMs; + } + + public Endpoint getEndpoint() { + return mEndpoint; + } + + public static class Endpoint { + @SerializedName("browseEndpoint") + private BrowseEndpoint mBrowseEndpoint; + + @SerializedName("watchEndpoint") + private WatchEndpoint mWatchEndpoint; + + public BrowseEndpoint getBrowseEndpoint() { + return mBrowseEndpoint; + } + + public WatchEndpoint getWatchEndpoint() { + return mWatchEndpoint; + } + + public static class BrowseEndpoint { + @SerializedName("browseId") + private String mBrowseId; // channelId or playlistId + + public String getBrowseId() { + return mBrowseId; + } + } + + public static class WatchEndpoint { + @SerializedName("videoId") + private String mVideoId; + + public String getVideoId() { + return mVideoId; + } + } + } +} \ No newline at end of file diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenRenderer.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenRenderer.java new file mode 100644 index 000000000..ab13d52e8 --- /dev/null +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenRenderer.java @@ -0,0 +1,22 @@ +package com.liskovsoft.youtubeapi.next.v1.models; + +import com.google.gson.annotations.SerializedName; +import java.util.List; + +public class EndScreenRenderer { + @SerializedName("elements") + private List mElements; + + public List getElements() { + return mElements; + } + + public static class ElementWrapper { + @SerializedName("endscreenElementRenderer") + private EndScreenElement mElement; + + public EndScreenElement getElement() { + return mElement; + } + } +} \ No newline at end of file diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/result/WatchNextResult.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/result/WatchNextResult.java index c88fd73fb..c3fe76584 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/result/WatchNextResult.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/result/WatchNextResult.java @@ -9,6 +9,7 @@ import com.liskovsoft.youtubeapi.next.v1.models.Playlist; import com.liskovsoft.youtubeapi.next.v1.models.SuggestedSection; import com.liskovsoft.youtubeapi.next.v1.models.VideoOwner; +import com.liskovsoft.youtubeapi.next.v1.models.EndScreen; import java.util.List; @@ -35,6 +36,8 @@ public class WatchNextResult { private ItemWrapper mReplayItem; @JsonPath("$.transportControls.transportControlsRenderer") private ButtonStates mButtonStates; + @JsonPath("$.endscreen") + private EndScreen mEndScreen; public List getSuggestedSections() { return mSuggestedSections; @@ -71,4 +74,8 @@ public ButtonStates getButtonStates() { public VideoItem getVideoDetails() { return mVideoDetails; } + + public EndScreen getEndScreen() { + return mEndScreen; + } } diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java new file mode 100644 index 000000000..9a62808f8 --- /dev/null +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java @@ -0,0 +1,127 @@ +package com.liskovsoft.youtubeapi.service.data; + +import com.liskovsoft.mediaserviceinterfaces.data.EndScreenItem; +import com.liskovsoft.sharedutils.helpers.Helpers; +import com.liskovsoft.youtubeapi.next.v1.models.EndScreenElement; +import com.liskovsoft.googlecommon.common.helpers.YouTubeHelper; + +public class YouTubeEndScreenItem implements EndScreenItem { + private int mType; + private String mTitle; + private String mMetadata; + private String mImageUrl; + private String mId; + private long mStartTimeMs; + private long mEndTimeMs; + private float mLeft; + private float mTop; + private float mWidth; + private float mAspectRatio; + + public static YouTubeEndScreenItem from(EndScreenElement element) { + if (element == null) { + return null; + } + + YouTubeEndScreenItem item = new YouTubeEndScreenItem(); + + // Determine type + String style = element.getStyle(); + if ("VIDEO".equals(style)) { + item.mType = TYPE_VIDEO; + } else if ("CHANNEL".equals(style)) { + item.mType = TYPE_CHANNEL; + } else if ("PLAYLIST".equals(style)) { + item.mType = TYPE_PLAYLIST; + } else { + item.mType = TYPE_UNKNOWN; + } + + // Extract text content + item.mTitle = element.getTitle() != null ? element.getTitle().toString() : null; + item.mMetadata = element.getMetadata() != null ? element.getMetadata().toString() : null; + + // Extract image URL + if (element.getImage() != null) { + item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(element.getImage().getThumbnails()); + } + + // Extract timing + item.mStartTimeMs = Helpers.parseLong(element.getStartMs()); + item.mEndTimeMs = Helpers.parseLong(element.getEndMs()); + + // Extract positioning + item.mLeft = element.getLeft(); + item.mTop = element.getTop(); + item.mWidth = element.getWidth(); + item.mAspectRatio = element.getAspectRatio(); + + // Extract ID based on endpoint type + if (element.getEndpoint() != null) { + EndScreenElement.Endpoint endpoint = element.getEndpoint(); + + if (endpoint.getWatchEndpoint() != null) { + item.mId = endpoint.getWatchEndpoint().getVideoId(); + } else if (endpoint.getBrowseEndpoint() != null) { + item.mId = endpoint.getBrowseEndpoint().getBrowseId(); + } + } + + return item; + } + + @Override + public int getType() { + return mType; + } + + @Override + public String getTitle() { + return mTitle; + } + + @Override + public String getMetadata() { + return mMetadata; + } + + @Override + public String getImageUrl() { + return mImageUrl; + } + + @Override + public String getId() { + return mId; + } + + @Override + public long getStartTimeMs() { + return mStartTimeMs; + } + + @Override + public long getEndTimeMs() { + return mEndTimeMs; + } + + @Override + public float getLeft() { + return mLeft; + } + + @Override + public float getTop() { + return mTop; + } + + @Override + public float getWidth() { + return mWidth; + } + + @Override + public float getAspectRatio() { + return mAspectRatio; + } +} \ No newline at end of file diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeMediaItemMetadata.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeMediaItemMetadata.java index 5cf68ffe6..00e7fb9fe 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeMediaItemMetadata.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeMediaItemMetadata.java @@ -6,11 +6,14 @@ import com.liskovsoft.mediaserviceinterfaces.data.MediaItemMetadata; import com.liskovsoft.mediaserviceinterfaces.data.NotificationState; import com.liskovsoft.mediaserviceinterfaces.data.PlaylistInfo; +import com.liskovsoft.mediaserviceinterfaces.data.EndScreenItem; import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.sharedutils.mylogger.Log; import com.liskovsoft.youtubeapi.browse.v1.models.sections.Chip; import com.liskovsoft.youtubeapi.common.models.items.VideoItem; import com.liskovsoft.youtubeapi.next.v1.models.ButtonStates; +import com.liskovsoft.youtubeapi.next.v1.models.EndScreen; +import com.liskovsoft.youtubeapi.next.v1.models.EndScreenRenderer; import com.liskovsoft.youtubeapi.next.v1.models.SuggestedSection; import com.liskovsoft.youtubeapi.next.v1.models.VideoMetadata; import com.liskovsoft.youtubeapi.next.v1.models.VideoOwner; @@ -42,6 +45,7 @@ public class YouTubeMediaItemMetadata implements MediaItemMetadata { private List mSuggestions; private boolean mIsLive; private boolean mIsUpcoming; + private List mEndScreenItems; private PlaylistInfo mPlaylistInfo; public static YouTubeMediaItemMetadata from(WatchNextResult watchNextResult) { @@ -159,6 +163,21 @@ public static YouTubeMediaItemMetadata from(WatchNextResult watchNextResult) { } } + // Parse end screen + EndScreen endScreen = watchNextResult.getEndScreen(); + if (endScreen != null && endScreen.getRenderer() != null) { + EndScreenRenderer renderer = endScreen.getRenderer(); + if (renderer.getElements() != null) { + mediaItemMetadata.mEndScreenItems = new ArrayList<>(); + for (EndScreenRenderer.ElementWrapper wrapper : renderer.getElements()) { + YouTubeEndScreenItem item = YouTubeEndScreenItem.from(wrapper.getElement()); + if (item != null) { + mediaItemMetadata.mEndScreenItems.add(item); + } + } + } + } + return mediaItemMetadata; } @@ -325,4 +344,9 @@ public long getDurationMs() { public String getBadgeText() { return null; } + + @Override + public List getEndScreenItems() { + return mEndScreenItems; + } } From 3f35f157287acef9dce87cb34d91a552f1372b0f Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 18:53:59 -0300 Subject: [PATCH 2/7] feat: add getEndScreenItems stub to MediaItemMetadataImpl V2 API implementation returns null as end screens are not supported in V2. End screen support is only available in V1 API. --- .../youtubeapi/next/v2/impl/MediaItemMetadataImpl.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v2/impl/MediaItemMetadataImpl.kt b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v2/impl/MediaItemMetadataImpl.kt index f0f271641..cc77db4fc 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v2/impl/MediaItemMetadataImpl.kt +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v2/impl/MediaItemMetadataImpl.kt @@ -312,4 +312,8 @@ internal data class MediaItemMetadataImpl(private val watchNextResult: WatchNext override fun getBadgeText(): String? { return badgeTextItem } -} + + override fun getEndScreenItems(): MutableList? { + return null // V2 API doesn't support end screens yet + } +} \ No newline at end of file From 00840463680abec5aac3633945a8bf4cb4d1ab20 Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 19:12:53 -0300 Subject: [PATCH 3/7] fix: correct imports in EndScreenElement and YouTubeEndScreenItem - Replace CommonItems.Thumbnail with ThumbnailItem - Fix thumbnail URL extraction using getThumbnails() - Ensure compatibility with existing codebase structure --- .../youtubeapi/next/v1/models/EndScreenElement.java | 6 +++--- .../youtubeapi/service/data/YouTubeEndScreenItem.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java index 28907de8d..e676d7b12 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/next/v1/models/EndScreenElement.java @@ -2,14 +2,14 @@ import com.google.gson.annotations.SerializedName; import com.liskovsoft.googlecommon.common.models.V2.TextItem; -import com.liskovsoft.youtubeapi.common.models.gen.CommonItems; +import com.liskovsoft.youtubeapi.common.models.gen.ThumbnailItem; public class EndScreenElement { @SerializedName("style") private String mStyle; // "CHANNEL", "VIDEO", "PLAYLIST" @SerializedName("image") - private CommonItems.Thumbnail mImage; + private ThumbnailItem mImage; @SerializedName("title") private TextItem mTitle; @@ -42,7 +42,7 @@ public String getStyle() { return mStyle; } - public CommonItems.Thumbnail getImage() { + public ThumbnailItem getImage() { return mImage; } diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java index 9a62808f8..578d5075a 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java @@ -42,7 +42,7 @@ public static YouTubeEndScreenItem from(EndScreenElement element) { item.mMetadata = element.getMetadata() != null ? element.getMetadata().toString() : null; // Extract image URL - if (element.getImage() != null) { + if (element.getImage() != null && element.getImage().getThumbnails() != null) { item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(element.getImage().getThumbnails()); } @@ -59,7 +59,7 @@ public static YouTubeEndScreenItem from(EndScreenElement element) { // Extract ID based on endpoint type if (element.getEndpoint() != null) { EndScreenElement.Endpoint endpoint = element.getEndpoint(); - + if (endpoint.getWatchEndpoint() != null) { item.mId = endpoint.getWatchEndpoint().getVideoId(); } else if (endpoint.getBrowseEndpoint() != null) { From 5fd621e0f0b62a89e2a73593de7aef5c9f5488ba Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 19:37:53 -0300 Subject: [PATCH 4/7] fix: use correct YouTubeHelper for thumbnail URL extraction - Use youtubeapi.common.helpers.YouTubeHelper instead of googlecommon version - Pass ThumbnailItem directly instead of getThumbnails() list - Fix type compatibility issue with findOptimalResThumbnailUrl --- .../youtubeapi/service/data/YouTubeEndScreenItem.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java index 578d5075a..032991031 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java @@ -3,7 +3,7 @@ import com.liskovsoft.mediaserviceinterfaces.data.EndScreenItem; import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.youtubeapi.next.v1.models.EndScreenElement; -import com.liskovsoft.googlecommon.common.helpers.YouTubeHelper; +import com.liskovsoft.youtubeapi.common.helpers.YouTubeHelper; public class YouTubeEndScreenItem implements EndScreenItem { private int mType; @@ -41,9 +41,9 @@ public static YouTubeEndScreenItem from(EndScreenElement element) { item.mTitle = element.getTitle() != null ? element.getTitle().toString() : null; item.mMetadata = element.getMetadata() != null ? element.getMetadata().toString() : null; - // Extract image URL - if (element.getImage() != null && element.getImage().getThumbnails() != null) { - item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(element.getImage().getThumbnails()); + // Extract image URL using gen helper + if (element.getImage() != null) { + item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(element.getImage()); } // Extract timing From db5e3c55c93a5bc740347d75b79fa221f4c25ccb Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 20:04:47 -0300 Subject: [PATCH 5/7] fix: correct end screen implementation with proper types - Add EndScreenElement.getThumbnails() Kotlin extension - Use ThumbnailItem for image field in EndScreenElement - Import Kotlin extension in YouTubeEndScreenItem using static import - Add getEndScreenItems() stub to V2 implementation (returns null) - Fix thumbnail URL extraction using CommonHelperKt.getThumbnails --- .../youtubeapi/common/models/gen/CommonHelper.kt | 5 +++++ .../youtubeapi/service/data/YouTubeEndScreenItem.java | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt index 6754e805d..75418db11 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt @@ -402,4 +402,9 @@ internal fun ResponseContext.getSuggestToken(): String? = serviceTrackingParams? if (it?.service == SERVICE_SUGGEST) { it.params?.firstOrNull { it?.key == KEY_SUGGEST_TOKEN }?.value } else null + +//////////// +// End Screen Support + +internal fun EndScreenElement.getThumbnails() = image?.thumbnails } \ No newline at end of file diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java index 032991031..1348071c3 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/service/data/YouTubeEndScreenItem.java @@ -3,7 +3,9 @@ import com.liskovsoft.mediaserviceinterfaces.data.EndScreenItem; import com.liskovsoft.sharedutils.helpers.Helpers; import com.liskovsoft.youtubeapi.next.v1.models.EndScreenElement; -import com.liskovsoft.youtubeapi.common.helpers.YouTubeHelper; +import com.liskovsoft.googlecommon.common.helpers.YouTubeHelper; + +import static com.liskovsoft.youtubeapi.common.models.gen.CommonHelperKt.getThumbnails; public class YouTubeEndScreenItem implements EndScreenItem { private int mType; @@ -41,9 +43,9 @@ public static YouTubeEndScreenItem from(EndScreenElement element) { item.mTitle = element.getTitle() != null ? element.getTitle().toString() : null; item.mMetadata = element.getMetadata() != null ? element.getMetadata().toString() : null; - // Extract image URL using gen helper + // Extract image URL using Kotlin extension if (element.getImage() != null) { - item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(element.getImage()); + item.mImageUrl = YouTubeHelper.findOptimalResThumbnailUrl(getThumbnails(element)); } // Extract timing From d41fb3bd5cb158952d1b3717064ebf9d7f8024cf Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 20:13:09 -0300 Subject: [PATCH 6/7] fix: add missing import for EndScreenElement in CommonHelper - Import EndScreenElement at the top of CommonHelper.kt - Ensure Kotlin extension function compiles correctly --- .../com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt index 75418db11..0dd495987 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt @@ -8,6 +8,7 @@ import com.liskovsoft.youtubeapi.browse.v2.gen.getThumbnails import com.liskovsoft.youtubeapi.browse.v2.gen.getVideoId import com.liskovsoft.googlecommon.common.helpers.ServiceHelper import com.liskovsoft.youtubeapi.next.v2.gen.getContinuationToken +import com.liskovsoft.youtubeapi.next.v1.models.EndScreenElement // A badge before the image private const val BADGE_STYLE_LIVE = "LIVE" From 301d92b7e78f92c0badf573ba0f3f79fc02a7d78 Mon Sep 17 00:00:00 2001 From: Eutalix Date: Thu, 9 Apr 2026 20:34:07 -0300 Subject: [PATCH 7/7] fix: add EndScreenElement Kotlin extension at correct scope - Add getThumbnails() extension at top level (not inside function) - Import EndScreenElement at file header - Ensure proper Kotlin syntax and scope --- .../youtubeapi/common/models/gen/CommonHelper.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt index 0dd495987..646666d6f 100644 --- a/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt +++ b/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/common/models/gen/CommonHelper.kt @@ -1,14 +1,14 @@ package com.liskovsoft.youtubeapi.common.models.gen import com.liskovsoft.googlecommon.common.helpers.YouTubeHelper -import com.liskovsoft.mediaserviceinterfaces.data.MediaItem -import com.liskovsoft.sharedutils.helpers.DateHelper import com.liskovsoft.youtubeapi.browse.v2.gen.getContinuationToken import com.liskovsoft.youtubeapi.browse.v2.gen.getThumbnails import com.liskovsoft.youtubeapi.browse.v2.gen.getVideoId import com.liskovsoft.googlecommon.common.helpers.ServiceHelper import com.liskovsoft.youtubeapi.next.v2.gen.getContinuationToken import com.liskovsoft.youtubeapi.next.v1.models.EndScreenElement +import com.liskovsoft.mediaserviceinterfaces.data.MediaItem +import com.liskovsoft.sharedutils.helpers.DateHelper // A badge before the image private const val BADGE_STYLE_LIVE = "LIVE" @@ -403,9 +403,9 @@ internal fun ResponseContext.getSuggestToken(): String? = serviceTrackingParams? if (it?.service == SERVICE_SUGGEST) { it.params?.firstOrNull { it?.key == KEY_SUGGEST_TOKEN }?.value } else null - +} + //////////// // End Screen Support -internal fun EndScreenElement.getThumbnails() = image?.thumbnails -} \ No newline at end of file +internal fun EndScreenElement.getThumbnails() = image?.thumbnails \ No newline at end of file