diff --git a/spec/invidious/videos/lockup_videos_extract_spec.cr b/spec/invidious/videos/lockup_videos_extract_spec.cr new file mode 100644 index 000000000..0b60d7eb1 --- /dev/null +++ b/spec/invidious/videos/lockup_videos_extract_spec.cr @@ -0,0 +1,63 @@ +require "../../parsers_helper.cr" + +# Wraps a raw lockupViewModel the same way YouTube encapsulates it in a +# channel videos tab (richGridRenderer -> richItemRenderer -> content). +private def wrap_lockup(lockup : JSON::Any) : Hash(String, JSON::Any) + wrapped = { + "twoColumnBrowseResultsRenderer" => { + "tabs" => [{ + "tabRenderer" => { + "selected" => true, + "content" => { + "richGridRenderer" => { + "contents" => [{"richItemRenderer" => {"content" => {"lockupViewModel" => lockup}}}], + }, + }, + }, + }], + }, + } + + return JSON.parse(wrapped.to_json).as_h +end + +Spectator.describe "extract_items" do + # Real InnerTube data, captured from a channel videos tab (2026-08). + # The collab video has an additional metadata row containing the channel + # names, which pushes the views/published data into the second row. + # See: https://github.com/iv-org/invidious/issues/5740 + COLLAB_VIDEO_LOCKUP = JSON.parse(%q({"contentImage":{"thumbnailViewModel":{"image":{"sources":[{"url":"https://i.ytimg.com/vi/kS-CGkiPetQ/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLCIllUNjYj70p7C0pXUJdEh20roxA","width":168,"height":94},{"url":"https://i.ytimg.com/vi/kS-CGkiPetQ/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLD7uxdjDGIpBNvu6yYOFWqoJlit8A","width":196,"height":110},{"url":"https://i.ytimg.com/vi/kS-CGkiPetQ/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBAmbS9wr6h7ivyV54-07jE0ojoWQ","width":246,"height":138},{"url":"https://i.ytimg.com/vi/kS-CGkiPetQ/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLCcXKobyVI6zP8JsvHMG8YqXDPDtQ","width":336,"height":188}]},"overlays":[{"thumbnailBottomOverlayViewModel":{"badges":[{"thumbnailBadgeViewModel":{"text":"29:54","badgeStyle":"THUMBNAIL_OVERLAY_BADGE_STYLE_DEFAULT","animationActivationTargetId":"kS-CGkiPetQ","animationActivationEntityKey":"Eh8veW91dHViZS9hcHAvd2F0Y2gvcGxheWVyX3N0YXRlIMMCKAE%3D","lottieData":{"url":"https://www.gstatic.com/youtube/img/lottie/audio_indicator/audio_indicator_v2.json","settings":{"loop":true,"autoplay":true}},"animatedText":"Now playing","animationActivationEntitySelectorType":"THUMBNAIL_BADGE_ANIMATION_ENTITY_SELECTOR_TYPE_PLAYER_STATE","rendererContext":{"accessibilityContext":{"label":"29 minutes, 54 seconds"}}}}]}},{"animatedThumbnailOverlayViewModel":{"thumbnail":{"sources":[{"url":"https://i.ytimg.com/an_webp/kS-CGkiPetQ/mqdefault_6s.webp?du=3000&sqp=CNTOpNQG&rs=AOn4CLDfiSn0IJCUaP_rtwMtOdm0W_mRKg","width":320,"height":180}]}}},{"thumbnailHoverOverlayToggleActionsViewModel":{"buttons":[{"toggleButtonViewModel":{"defaultButtonViewModel":{"buttonViewModel":{"iconName":"WATCH_LATER","onTap":{"innertubeCommand":{"clickTrackingParams":"CKgCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/browse/edit_playlist"}},"playlistEditEndpoint":{"playlistId":"WL","actions":[{"addedVideoId":"kS-CGkiPetQ","action":"ACTION_ADD_VIDEO"}]}}},"accessibilityText":"Watch later","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CKgCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"toggledButtonViewModel":{"buttonViewModel":{"iconName":"CHECK","onTap":{"innertubeCommand":{"clickTrackingParams":"CKcCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/browse/edit_playlist"}},"playlistEditEndpoint":{"playlistId":"WL","actions":[{"action":"ACTION_REMOVE_VIDEO_BY_VIDEO_ID","removedVideoId":"kS-CGkiPetQ"}]}}},"accessibilityText":"Added","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CKcCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"isToggled":false,"trackingParams":"CJ8CENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA=="}},{"toggleButtonViewModel":{"defaultButtonViewModel":{"buttonViewModel":{"iconName":"ADD_TO_QUEUE_TAIL","onTap":{"innertubeCommand":{"clickTrackingParams":"CKYCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true}},"signalServiceEndpoint":{"signal":"CLIENT_SIGNAL","actions":[{"clickTrackingParams":"CKYCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","addToPlaylistCommand":{"openMiniplayer":true,"videoId":"kS-CGkiPetQ","listType":"PLAYLIST_EDIT_LIST_TYPE_QUEUE","onCreateListCommand":{"clickTrackingParams":"CKYCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/playlist/create"}},"createPlaylistServiceEndpoint":{"videoIds":["kS-CGkiPetQ"],"params":"CAQ%3D"}},"videoIds":["kS-CGkiPetQ"],"videoCommand":{"clickTrackingParams":"CKYCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=kS-CGkiPetQ","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"kS-CGkiPetQ","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr5---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=912f821a488f7ad4&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}]}}},"accessibilityText":"Add to queue","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CKYCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"toggledButtonViewModel":{"buttonViewModel":{"iconName":"CHECK","accessibilityText":"Added","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CKUCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"isToggled":false,"trackingParams":"CJ8CENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA=="}}]}}]}},"metadata":{"lockupMetadataViewModel":{"title":{"content":"Google Maps is unreasonably fast. Let me explain"},"metadata":{"contentMetadataViewModel":{"metadataRows":[{"metadataParts":[{"text":{"content":"Veritasium and 2swap","styleRuns":[{"startIndex":0,"length":20},{"startIndex":10,"length":1,"styleRunExtensions":{"styleRunColorMapExtension":{"colorMap":[{"key":"USER_INTERFACE_THEME_DARK","value":4289374890},{"key":"USER_INTERFACE_THEME_LIGHT","value":4284506208}]}}},{"startIndex":20,"styleRunExtensions":{"styleRunColorMapExtension":{"colorMap":[{"key":"USER_INTERFACE_THEME_DARK","value":4289374890},{"key":"USER_INTERFACE_THEME_LIGHT","value":4284506208}]}}}],"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"},{"startIndex":20,"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"}]}}]},{"metadataParts":[{"text":{"content":"7.9M views"}},{"text":{"content":"2 months ago"},"accessibilityLabel":"2 months ago"}]}],"delimiter":" \u2022 "}},"menuButton":{"buttonViewModel":{"iconName":"MORE_VERT","onTap":{"innertubeCommand":{"clickTrackingParams":"CKACEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","showSheetCommand":{"panelLoadingStrategy":{"inlineContent":{"sheetViewModel":{"content":{"listViewModel":{"listItems":[{"listItemViewModel":{"title":{"content":"Add to queue"},"leadingImage":{"sources":[{"clientResource":{"imageName":"ADD_TO_QUEUE_TAIL"}}]},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CKQCEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CKQCEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true}},"signalServiceEndpoint":{"signal":"CLIENT_SIGNAL","actions":[{"clickTrackingParams":"CKQCEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","addToPlaylistCommand":{"openMiniplayer":true,"videoId":"kS-CGkiPetQ","listType":"PLAYLIST_EDIT_LIST_TYPE_QUEUE","onCreateListCommand":{"clickTrackingParams":"CKQCEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/playlist/create"}},"createPlaylistServiceEndpoint":{"videoIds":["kS-CGkiPetQ"],"params":"CAQ%3D"}},"videoIds":["kS-CGkiPetQ"],"videoCommand":{"clickTrackingParams":"CKQCEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=kS-CGkiPetQ","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"kS-CGkiPetQ","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr5---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=912f821a488f7ad4&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}]}}}}}}},{"listItemViewModel":{"title":{"content":"Save to playlist"},"leadingImage":{"sources":[{"clientResource":{"imageName":"BOOKMARK_BORDER"}}]},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CKMCEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CKMCEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","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":"CKMCEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","showSheetCommand":{"panelLoadingStrategy":{"requestTemplate":{"panelId":"PAadd_to_playlist","params":"-gYNCgtrUy1DR2tpUGV0UQ%3D%3D"}}}}}}}}}}},{"downloadListItemViewModel":{"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CKICENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CKICENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","offlineVideoEndpoint":{"videoId":"kS-CGkiPetQ","onAddCommand":{"clickTrackingParams":"CKICENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","getDownloadActionCommand":{"videoId":"kS-CGkiPetQ","params":"CAIQAA%3D%3D","isCrossDeviceDownload":false}}}}}}}}},{"listItemViewModel":{"title":{"content":"Share"},"leadingImage":{"sources":[{"clientResource":{"imageName":"SHARE"}}]},"rendererContext":{"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CKACEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/share/get_share_panel"}},"shareEntityServiceEndpoint":{"serializedShareEntity":"CgtrUy1DR2tpUGV0UQ%3D%3D","commands":[{"clickTrackingParams":"CKACEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","openPopupAction":{"popup":{"unifiedSharePanelRenderer":{"trackingParams":"CKECEI5iIhMI6bLazNGzlgMVNaHRBB2Jlw0U","showLoadingSpinner":true}},"popupType":"DIALOG","beReused":true}}]}}}}}}}]}}}}}}}},"accessibilityText":"More actions","style":"BUTTON_VIEW_MODEL_STYLE_MONO","trackingParams":"CKACEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TEXT","buttonSize":"BUTTON_VIEW_MODEL_SIZE_DEFAULT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}}}},"contentId":"kS-CGkiPetQ","contentType":"LOCKUP_CONTENT_TYPE_VIDEO","themedPalette":{"lightThemePalette":{"baseBackground":4294440951,"raisedBackground":4294440951,"additiveBackground":562530183,"textPrimary":4280295456,"textSecondary":4283716692,"outline":858796080,"keyLight":4291085508,"collectionStack":4289111718,"invertedBackground":4283716692,"textPrimaryInverse":4294440951,"textDisabled":2133864496,"dropShadow":428312455,"cardOutline":176654215,"overlayBackground":3424657440,"overlayTextPrimary":4294440951,"solidWash":4283716692,"solidRim":870244062,"tonalWash":871888887,"tonalRim":868533444,"outlineRim":1291319287,"solidWashInverse":4292796126,"solidRimInverse":2146299373,"tonalWashInverse":653785079,"tonalRimInverse":653127149,"outlineRimInverse":653785079,"solidBackground":4281348144,"solidBackgroundInverse":4289111718,"tonalBackground":866559654,"tonalBackgroundInverse":434036446,"outlineInverse":871230957,"directionalLightStopZero":4289111718,"directionalLightStopOne":15592941},"darkThemePalette":{"baseBackground":4279176975,"raisedBackground":4280295456,"additiveBackground":730302343,"textPrimary":4293783021,"textSecondary":4291085508,"outline":1071570654,"keyLight":4282532418,"collectionStack":4283716692,"invertedBackground":4289111718,"textPrimaryInverse":4279176975,"textDisabled":2145312478,"dropShadow":428312455,"cardOutline":176654215,"overlayBackground":3424657440,"overlayTextPrimary":4294440951,"solidWash":4292796126,"solidRim":2146299373,"tonalWash":653785079,"tonalRim":653127149,"outlineRim":653785079,"solidWashInverse":4283716692,"solidRimInverse":870244062,"tonalWashInverse":871888887,"tonalRimInverse":868533444,"outlineRimInverse":1291319287,"solidBackground":4289111718,"solidBackgroundInverse":4281348144,"tonalBackground":434036446,"tonalBackgroundInverse":866559654,"outlineInverse":858796080,"directionalLightStopZero":4282532418,"directionalLightStopOne":4279176975}},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CJ8CENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA==","visibility":{"types":"12"}}},"accessibilityContext":{"label":"Google Maps is unreasonably fast. Let me explain 29 minutes"},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CJ8CENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFFoYVUNIbnlmTXFpUlJHMXUtMk1zU1FMYlhBmgEDEPI4ygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=kS-CGkiPetQ","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"kS-CGkiPetQ","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr5---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=912f821a488f7ad4&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}}})) + + REGULAR_VIDEO_LOCKUP = JSON.parse(%q({"contentImage":{"thumbnailViewModel":{"image":{"sources":[{"url":"https://i.ytimg.com/vi/J1WoNuemKOg/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLDLRkUyt_YYH3TScfBKy3EkNi5oxg","width":168,"height":94},{"url":"https://i.ytimg.com/vi/J1WoNuemKOg/hqdefault.jpg?sqp=-oaymwEbCMQBEG5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLAApqCXVQzdpKP38PWR-kNbg_-fEA","width":196,"height":110},{"url":"https://i.ytimg.com/vi/J1WoNuemKOg/hqdefault.jpg?sqp=-oaymwEcCPYBEIoBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLB5CKzL-E6bq_ERLviXU7arwNm9LA","width":246,"height":138},{"url":"https://i.ytimg.com/vi/J1WoNuemKOg/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLDlWz1RskmUwBarP_3TjyecMaeoBA","width":336,"height":188}]},"overlays":[{"thumbnailBottomOverlayViewModel":{"badges":[{"thumbnailBadgeViewModel":{"text":"22:45","badgeStyle":"THUMBNAIL_OVERLAY_BADGE_STYLE_DEFAULT","animationActivationTargetId":"J1WoNuemKOg","animationActivationEntityKey":"Eh8veW91dHViZS9hcHAvd2F0Y2gvcGxheWVyX3N0YXRlIMMCKAE%3D","lottieData":{"url":"https://www.gstatic.com/youtube/img/lottie/audio_indicator/audio_indicator_v2.json","settings":{"loop":true,"autoplay":true}},"animatedText":"Now playing","animationActivationEntitySelectorType":"THUMBNAIL_BADGE_ANIMATION_ENTITY_SELECTOR_TYPE_PLAYER_STATE","rendererContext":{"accessibilityContext":{"label":"22 minutes, 45 seconds"}}}}]}},{"animatedThumbnailOverlayViewModel":{"thumbnail":{"sources":[{"url":"https://i.ytimg.com/an_webp/J1WoNuemKOg/mqdefault_6s.webp?du=3000&sqp=CNiHpdQG&rs=AOn4CLBSgxdt2GtUo-uugCtBsE44-UC_Nw","width":320,"height":180}]}}},{"thumbnailHoverOverlayToggleActionsViewModel":{"buttons":[{"toggleButtonViewModel":{"defaultButtonViewModel":{"buttonViewModel":{"iconName":"WATCH_LATER","onTap":{"innertubeCommand":{"clickTrackingParams":"CPUCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/browse/edit_playlist"}},"playlistEditEndpoint":{"playlistId":"WL","actions":[{"addedVideoId":"J1WoNuemKOg","action":"ACTION_ADD_VIDEO"}]}}},"accessibilityText":"Watch later","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CPUCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"toggledButtonViewModel":{"buttonViewModel":{"iconName":"CHECK","onTap":{"innertubeCommand":{"clickTrackingParams":"CPQCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/browse/edit_playlist"}},"playlistEditEndpoint":{"playlistId":"WL","actions":[{"action":"ACTION_REMOVE_VIDEO_BY_VIDEO_ID","removedVideoId":"J1WoNuemKOg"}]}}},"accessibilityText":"Added","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CPQCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"isToggled":false,"trackingParams":"COwCENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA=="}},{"toggleButtonViewModel":{"defaultButtonViewModel":{"buttonViewModel":{"iconName":"ADD_TO_QUEUE_TAIL","onTap":{"innertubeCommand":{"clickTrackingParams":"CPMCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true}},"signalServiceEndpoint":{"signal":"CLIENT_SIGNAL","actions":[{"clickTrackingParams":"CPMCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","addToPlaylistCommand":{"openMiniplayer":true,"videoId":"J1WoNuemKOg","listType":"PLAYLIST_EDIT_LIST_TYPE_QUEUE","onCreateListCommand":{"clickTrackingParams":"CPMCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/playlist/create"}},"createPlaylistServiceEndpoint":{"videoIds":["J1WoNuemKOg"],"params":"CAQ%3D"}},"videoIds":["J1WoNuemKOg"],"videoCommand":{"clickTrackingParams":"CPMCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=J1WoNuemKOg","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"J1WoNuemKOg","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr3---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=2755a836e7a628e8&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}]}}},"accessibilityText":"Add to queue","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CPMCEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"toggledButtonViewModel":{"buttonViewModel":{"iconName":"CHECK","accessibilityText":"Added","style":"BUTTON_VIEW_MODEL_STYLE_OVERLAY_DARK","trackingParams":"CPICEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TONAL","buttonSize":"BUTTON_VIEW_MODEL_SIZE_COMPACT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}},"isToggled":false,"trackingParams":"COwCENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA=="}}]}}]}},"metadata":{"lockupMetadataViewModel":{"title":{"content":"Total Solar Eclipse from 92,000 Feet"},"metadata":{"contentMetadataViewModel":{"metadataRows":[{"metadataParts":[{"text":{"content":"1.6M views"}},{"text":{"content":"4 days ago"},"accessibilityLabel":"4 days ago"}]}],"delimiter":" \u2022 "}},"menuButton":{"buttonViewModel":{"iconName":"MORE_VERT","onTap":{"innertubeCommand":{"clickTrackingParams":"CO0CEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","showSheetCommand":{"panelLoadingStrategy":{"inlineContent":{"sheetViewModel":{"content":{"listViewModel":{"listItems":[{"listItemViewModel":{"title":{"content":"Add to queue"},"leadingImage":{"sources":[{"clientResource":{"imageName":"ADD_TO_QUEUE_TAIL"}}]},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CPECEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CPECEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true}},"signalServiceEndpoint":{"signal":"CLIENT_SIGNAL","actions":[{"clickTrackingParams":"CPECEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","addToPlaylistCommand":{"openMiniplayer":true,"videoId":"J1WoNuemKOg","listType":"PLAYLIST_EDIT_LIST_TYPE_QUEUE","onCreateListCommand":{"clickTrackingParams":"CPECEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/playlist/create"}},"createPlaylistServiceEndpoint":{"videoIds":["J1WoNuemKOg"],"params":"CAQ%3D"}},"videoIds":["J1WoNuemKOg"],"videoCommand":{"clickTrackingParams":"CPECEP6YBBgAIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=J1WoNuemKOg","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"J1WoNuemKOg","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr3---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=2755a836e7a628e8&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}]}}}}}}},{"listItemViewModel":{"title":{"content":"Save to playlist"},"leadingImage":{"sources":[{"clientResource":{"imageName":"BOOKMARK_BORDER"}}]},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CPACEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CPACEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","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":"CPACEJSsCRgBIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","showSheetCommand":{"panelLoadingStrategy":{"requestTemplate":{"panelId":"PAadd_to_playlist","params":"-gYNCgtKMVdvTnVlbUtPZw%3D%3D"}}}}}}}}}}},{"downloadListItemViewModel":{"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"CO8CENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0U","visibility":{"types":"12"}}},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CO8CENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","offlineVideoEndpoint":{"videoId":"J1WoNuemKOg","onAddCommand":{"clickTrackingParams":"CO8CENGqBRgCIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","getDownloadActionCommand":{"videoId":"J1WoNuemKOg","params":"CAIQAA%3D%3D","isCrossDeviceDownload":false}}}}}}}}},{"listItemViewModel":{"title":{"content":"Share"},"leadingImage":{"sources":[{"clientResource":{"imageName":"SHARE"}}]},"rendererContext":{"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"CO0CEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"sendPost":true,"apiUrl":"/youtubei/v1/share/get_share_panel"}},"shareEntityServiceEndpoint":{"serializedShareEntity":"CgtKMVdvTnVlbUtPZw%3D%3D","commands":[{"clickTrackingParams":"CO0CEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0UygEEzZdbfg==","openPopupAction":{"popup":{"unifiedSharePanelRenderer":{"trackingParams":"CO4CEI5iIhMI6bLazNGzlgMVNaHRBB2Jlw0U","showLoadingSpinner":true}},"popupType":"DIALOG","beReused":true}}]}}}}}}}]}}}}}}}},"accessibilityText":"More actions","style":"BUTTON_VIEW_MODEL_STYLE_MONO","trackingParams":"CO0CEPBbIhMI6bLazNGzlgMVNaHRBB2Jlw0U","type":"BUTTON_VIEW_MODEL_TYPE_TEXT","buttonSize":"BUTTON_VIEW_MODEL_SIZE_DEFAULT","state":"BUTTON_VIEW_MODEL_STATE_ACTIVE"}}}},"contentId":"J1WoNuemKOg","contentType":"LOCKUP_CONTENT_TYPE_VIDEO","themedPalette":{"lightThemePalette":{"baseBackground":4293982207,"raisedBackground":4293982207,"additiveBackground":558269897,"textPrimary":4278787895,"textSecondary":4281619317,"outline":856895310,"keyLight":4289250272,"collectionStack":4286883015,"invertedBackground":4279849616,"textPrimaryInverse":4293982207,"textDisabled":2131963726,"dropShadow":424052169,"cardOutline":172393929,"overlayBackground":3423149879,"overlayTextPrimary":4293982207,"solidWash":4281619317,"solidRim":868867571,"tonalWash":871430143,"tonalRim":866698208,"outlineRim":1290860543,"solidWashInverse":4291419635,"solidRimInverse":2145447419,"tonalWashInverse":653326335,"tonalRimInverse":652275195,"outlineRimInverse":653326335,"solidBackground":4279447374,"solidBackgroundInverse":4286883015,"tonalBackground":864330951,"tonalBackgroundInverse":432659955,"outlineInverse":870379003,"directionalLightStopZero":4286361059,"directionalLightStopOne":14740987},"darkThemePalette":{"baseBackground":4278325020,"raisedBackground":4278787895,"additiveBackground":726042057,"textPrimary":4292931067,"textSecondary":4289250272,"outline":1070194163,"keyLight":4280500577,"collectionStack":4281619317,"invertedBackground":4286361059,"textPrimaryInverse":4278325020,"textDisabled":2143935987,"dropShadow":424052169,"cardOutline":172393929,"overlayBackground":3423149879,"overlayTextPrimary":4293982207,"solidWash":4291419635,"solidRim":2145447419,"tonalWash":653326335,"tonalRim":652275195,"outlineRim":653326335,"solidWashInverse":4281619317,"solidRimInverse":868867571,"tonalWashInverse":871430143,"tonalRimInverse":866698208,"outlineRimInverse":1290860543,"solidBackground":4286883015,"solidBackgroundInverse":4279447374,"tonalBackground":432659955,"tonalBackgroundInverse":864330951,"outlineInverse":856895310,"directionalLightStopZero":4280500577,"directionalLightStopOne":4278325020}},"rendererContext":{"loggingContext":{"loggingDirectives":{"trackingParams":"COwCENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFA==","visibility":{"types":"12"}}},"accessibilityContext":{"label":"Total Solar Eclipse from 92,000 Feet 22 minutes"},"commandContext":{"onTap":{"innertubeCommand":{"clickTrackingParams":"COwCENTEDCITCOmy2szRs5YDFTWh0QQdiZcNFFoYVUNIbnlmTXFpUlJHMXUtMk1zU1FMYlhBmgEDEPI4ygEEzZdbfg==","commandMetadata":{"webCommandMetadata":{"url":"/watch?v=J1WoNuemKOg","webPageType":"WEB_PAGE_TYPE_WATCH","rootVe":3832}},"watchEndpoint":{"videoId":"J1WoNuemKOg","watchEndpointSupportedOnesieConfig":{"html5PlaybackOnesieConfig":{"commonConfig":{"url":"https://rr3---sn-ugpjvh-ixms.googlevideo.com/initplayback?source=youtube&oeis=1&c=WEB&oad=3200&ovd=3200&oaad=11000&oavd=11000&ocs=700&oewis=1&oputc=1&olis=1&ofpcc=1&msp=1&odepv=1&id=2755a836e7a628e8&ip=186.150.226.223&initcwndbps=678750&mt=1787380855&oweuc="}}}}}}}}})) + + it "parses a regular channel video (views and published in first row)" do + items, _continuation = extract_items(wrap_lockup(REGULAR_VIDEO_LOCKUP), "Veritasium", "UCHnyfMqiRRG1u-2MsSQLbXA") + videos = items.select(SearchVideo) + + expect(videos.size).to eq(1) + + video = videos[0] + expect(video.id).to eq("J1WoNuemKOg") + expect(video.title).to eq("Total Solar Eclipse from 92,000 Feet") + expect(video.views).to eq(1_600_000) + expect((video.published - decode_date("4 days ago")).abs).to be < 1.second + expect(video.length_seconds).to eq(22*60 + 45) + end + + it "parses a collaboration channel video (extra metadata row with authors)" do + items, _continuation = extract_items(wrap_lockup(COLLAB_VIDEO_LOCKUP), "Veritasium", "UCHnyfMqiRRG1u-2MsSQLbXA") + videos = items.select(SearchVideo) + + expect(videos.size).to eq(1) + + video = videos[0] + expect(video.id).to eq("kS-CGkiPetQ") + expect(video.title).to eq("Google Maps is unreasonably fast. Let me explain") + + # Before the fix, views were 0 and published fell back to Time.local, + # because only metadataRows[0] (which contains the authors) was looked at. + expect(video.views).to eq(7_900_000) + expect((video.published - decode_date("2 months ago")).abs).to be < 1.second + expect(video.length_seconds).to eq(29*60 + 54) + end +end diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index b2226e74d..b906e8750 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -662,7 +662,12 @@ private module Parsers metadata = item_contents.dig("metadata", "lockupMetadataViewModel") title = metadata.dig("title", "content").as_s # Contains the views of the video and the published time of the video. - metadata_parts = metadata.dig("metadata", "contentMetadataViewModel", "metadataRows", 0, "metadataParts").try &.as_a + # NOTE: Collaboration videos have an additional metadata row containing + # the names of every channel involved, which means that the views and + # published data cannot be assumed to be located in the first row. + # See: https://github.com/iv-org/invidious/issues/5740 + metadata_parts = metadata.dig?("metadata", "contentMetadataViewModel", "metadataRows") + .try &.as_a.try(&.flat_map { |row| row.dig?("metadataParts").try(&.as_a) || [] of JSON::Any }) view_count_text = metadata_parts.try &.find { |item| item["icon"]?.nil? && item.dig?("text", "content").try &.as_s.includes?("views") } .try &.dig("text", "content").as_s