From bc162440e1189092195d15ccf5ff2686383e9dd2 Mon Sep 17 00:00:00 2001 From: Cameron Radmore Date: Mon, 10 Aug 2026 18:46:10 -0400 Subject: [PATCH 1/3] Channel home: add support for stations --- src/renderer/helpers/api/local.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index 0df5a6821f581..7f2fe6bfab1a4 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1824,6 +1824,7 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi } } case 'SHORT': + case 'STATION': case 'VIDEO': { let publishedText let lengthSeconds = '' @@ -1839,7 +1840,8 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi } /** @type {YTNodes.ThumbnailBottomOverlayView | undefined } */ - const thumbnailBottomOverlayView = lockupView.content_image?.overlays?.firstOfType(YTNodes.ThumbnailBottomOverlayView) + const thumbnailBottomOverlayView = lockupView.content_image?.overlays?.firstOfType(YTNodes.ThumbnailBottomOverlayView) ?? + lockupView.content_image?.primary_thumbnail?.overlays?.firstOfType(YTNodes.ThumbnailBottomOverlayView) if (thumbnailBottomOverlayView) { if (thumbnailBottomOverlayView.badges.some(badge => badge.badge_style === 'THUMBNAIL_OVERLAY_BADGE_STYLE_LIVE')) { From 3d968ee5f09805babd5b201ca3feefbaf5285e07 Mon Sep 17 00:00:00 2001 From: Cameron Radmore Date: Mon, 17 Aug 2026 19:56:01 -0400 Subject: [PATCH 2/3] support stations on search page (and hopefully recommended videos) --- src/renderer/helpers/api/local.js | 5 +++++ src/renderer/views/Watch/Watch.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index 7f2fe6bfab1a4..488400ac521d3 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1903,6 +1903,11 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi author = maybeAuthorText } + // I think this is only used for stations at the moment + if (author == null) { + author = lockupView.metadata?.metadata?.metadata_rows[0].metadata_parts?.[0].avatar_stack.text?.text + } + return { type: 'video', videoId: lockupView.content_id, diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js index d95dde49c6b9a..6222be1daf5f5 100644 --- a/src/renderer/views/Watch/Watch.js +++ b/src/renderer/views/Watch/Watch.js @@ -524,7 +524,7 @@ export default defineComponent({ this.recommendedVideos = result.watch_next_feed ?.filter((item) => { return item.type === 'CompactVideo' || item.type === 'CompactMovie' || - (item.type === 'LockupView' && item.content_type === 'VIDEO') + (item.type === 'LockupView' && (item.content_type === 'VIDEO' || item.content_type === 'STATION')) }) .map(parseLocalWatchNextVideo).filter(_ => _) // place watched recommended videos last From 6980f59c38fd17bdcf487468929c58c79040a250 Mon Sep 17 00:00:00 2001 From: Cameron Radmore Date: Mon, 31 Aug 2026 22:57:55 -0400 Subject: [PATCH 3/3] Display 'Station' instead of 'Live' --- .../components/FtListVideo/FtListVideo.vue | 34 ++++++++++++++----- src/renderer/helpers/api/local.js | 2 ++ static/locales/en-US.yaml | 1 + 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/renderer/components/FtListVideo/FtListVideo.vue b/src/renderer/components/FtListVideo/FtListVideo.vue index 832fb03f4d8bb..ce92697b80848 100644 --- a/src/renderer/components/FtListVideo/FtListVideo.vue +++ b/src/renderer/components/FtListVideo/FtListVideo.vue @@ -38,14 +38,29 @@ >
- {{ isLive ? t("Video.Live") : (isUpcoming ? t("Video.Upcoming") : displayDuration) }} + + + +
{{ t('Global.Counts.View Count', { count: parsedViewCount }, viewCount) }} • {{ uploadedTime }} • {{ t('Global.Counts.Watching Count', { count: parsedViewCount }, viewCount) }} @@ -412,6 +427,7 @@ const isVr360 = ref(false) const is3D = ref(false) const hasCaptions = ref(false) const isUpcoming = ref(false) +const isStation = ref(false) const isPremium = ref(false) const hideViews = ref(false) const deArrowTogglePinned = ref(false) @@ -1018,7 +1034,8 @@ function parseVideoData() { } description.value = props.data.description - isLive.value = props.data.liveNow || props.data.lengthSeconds === undefined + isStation.value = props.data.isStation === true + isLive.value = !isStation.value && (props.data.liveNow || props.data.lengthSeconds === undefined) isUpcoming.value = props.data.isUpcoming || props.data.premiere is4k.value = props.data.is4k is8k.value = props.data.is8k @@ -1042,7 +1059,7 @@ function parseVideoData() { } else if (props.data.premiereTimestamp !== undefined) { uploadedTime.value = new Date(props.data.premiereTimestamp * 1000).toLocaleString([locale.value, 'en']) published.value = props.data.premiereTimestamp * 1000 - } else if (typeof props.data.published === 'number' && !isLive.value) { + } else if (typeof props.data.published === 'number' && !isLive.value && !isStation.value) { published.value = props.data.published if (inHistory.value) { @@ -1077,6 +1094,7 @@ function markAsWatched() { watchProgress: 0, timeWatched: Date.now(), isLive: false, + isStation: false, type: 'video' } diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index 488400ac521d3..c1651a600d39c 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1826,6 +1826,7 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi case 'SHORT': case 'STATION': case 'VIDEO': { + const isStation = lockupView.content_type === 'STATION' let publishedText let lengthSeconds = '' let liveNow = false @@ -1919,6 +1920,7 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi lengthSeconds, liveNow, isUpcoming, + isStation, premiereDate } } diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml index 3fff1d0f079a1..4d358dddb31fd 100644 --- a/static/locales/en-US.yaml +++ b/static/locales/en-US.yaml @@ -889,6 +889,7 @@ Video: Premieres: Premieres Upcoming: Upcoming Unlisted: Unlisted + Station: Station Live: Live Live Now: Live Now Live Chat: Live Chat