From 59e7f9cba3f49ddea200775f59b2f326581fd4b0 Mon Sep 17 00:00:00 2001 From: Kelvin K <kelvin@futo.org> Date: Thu, 13 Jun 2024 17:44:45 +0200 Subject: [PATCH] Content recommendations support --- YoutubeScript.js | 63 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/YoutubeScript.js b/YoutubeScript.js index adbca06..5836ab0 100644 --- a/YoutubeScript.js +++ b/YoutubeScript.js @@ -483,6 +483,13 @@ source.getContentDetails = (url, useAuth) => { return source.getContentChapters(url, finalResult.__initialData); }; + finalResult.getContentRecommendations = function() { + const initialData = finalResult.__initialData; + if(!initialData) + return new VideoPager([], false); + return source.getContentRecommendations(url, initialData); + } + return finalResult; }; @@ -938,7 +945,46 @@ source.getSubComments = (comment) => { return new CommentPager([], false); }; +source.getContentRecommendations = (url, initialData) => { + useAuth = !!_settings?.authDetails; + url = convertIfOtherUrl(url); + + if(!initialData) { + const videoId = extractVideoIDFromUrl(url); + if(IS_TESTING) + console.log("VideoID:", videoId); + + const useLogin = useAuth && bridge.isLoggedIn(); + + const headersUsed = (useLogin) ? getAuthContextHeaders(false) : {}; + headersUsed["Accept-Language"] = "en-US"; + headersUsed["Cookie"] = "PREF=hl=en&gl=US" + + const resp = http.GET(url, headersUsed, useLogin); + + throwIfCaptcha(resp); + if(!resp.isOk) { + throw new ScriptException("Failed to request page [" + resp.code + "]"); + } + + const html = resp.body;//requestPage(url); + initialData = getInitialData(html); + } + + const contents = initialData.contents; + let watchNextFeed = contents.twoColumnWatchNextResults?.secondaryResults?.secondaryResults ?? null; + if(!watchNextFeed) + return new VideoPager([], false); + if(watchNextFeed.targetId != 'watch-next-feed' && watchNextFeed.results) + watchNextFeed = watchNextFeed.results.find(x=>x.targetId == 'watch-next-feed') + if(!watchNextFeed) + return new VideoPager([], false); + + const itemSectionRenderer = extractItemSectionRenderer_Shelves(watchNextFeed); + //TODO: pages + return new VideoPager(itemSectionRenderer?.videos ?? [], false); +}; //Channel source.isChannelUrl = (url) => { @@ -3204,11 +3250,12 @@ function extractSectionListRenderer_Sections(sectionListRenderer, contextData) { }; } function extractItemSectionRenderer_Shelves(itemSectionRenderer, contextData) { - const contents = itemSectionRenderer.contents; + const contents = itemSectionRenderer.contents ?? itemSectionRenderer.results; let shelves = []; let videos = []; let channels = []; let playlists = []; + let continuationToken = undefined; contents.forEach((item)=>{ switchKey(item, { @@ -3244,6 +3291,11 @@ function extractItemSectionRenderer_Shelves(itemSectionRenderer, contextData) { if(shelf.playlists.length > 0) playlists.push(...shelf.playlists); }, + continuationItemRenderer(renderer) { + const token = renderer?.continuationEndpoint?.continuationCommand?.token + if(token) + continuationToken = token; + }, default() { const video = switchKeyVideo(item, contextData); if(video) @@ -3257,7 +3309,8 @@ function extractItemSectionRenderer_Shelves(itemSectionRenderer, contextData) { shelves: shelves.filter(x=>x != null), videos: videos.filter(x=>x != null), channels: channels.filter(x=>x != null), - playlists: playlists.filter(x=>x != null) + playlists: playlists.filter(x=>x != null), + continuation: continuationToken }; } function extractGridRenderer_Shelf(gridRenderer, contextData) { @@ -3409,14 +3462,14 @@ function extractVideoWithContextRenderer_Video(videoRenderer, contextData) { contextData.authorLink : extractVideoWithContextRenderer_AuthorLink(videoRenderer); if(IS_TESTING) - console.log(videoRenderer); + ;//console.log(videoRenderer); if(!videoRenderer?.lengthText?.runs || !videoRenderer.publishedTimeText?.runs) isLive = true; //If no length, live after all? let viewCount = 0; - if(videoRenderer?.shortViewCountText?.runs != null) - viewCount = extractHumanNumber_Integer(extractRuns_String(videoRenderer.shortViewCountText.runs)); + if(videoRenderer?.shortViewCountText) + viewCount = extractHumanNumber_Integer(extractText_String(videoRenderer.shortViewCountText)); else log("No viewcount found on video " + videoRenderer.videoId); const title = (videoRenderer.headline) ? extractText_String(videoRenderer.headline) : extractText_String(videoRenderer.title); -- GitLab