From 4f171a68dcc5a20b5caafb59e1d5a0d3ddd34626 Mon Sep 17 00:00:00 2001 From: Kelvin <kelvin@futo.org> Date: Mon, 27 May 2024 17:45:22 +0200 Subject: [PATCH] Working getChannelPlaylists --- YoutubeConfig.json | 2 +- YoutubeScript.js | 110 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/YoutubeConfig.json b/YoutubeConfig.json index 10f5fe1..37c8daf 100644 --- a/YoutubeConfig.json +++ b/YoutubeConfig.json @@ -7,7 +7,7 @@ "sourceUrl": "https://plugins.grayjay.app/Youtube/YoutubeConfig.json", "repositoryUrl": "https://futo.org", "scriptUrl": "./YoutubeScript.js", - "version": 178, + "version": 179, "iconUrl": "./youtube.png", "id": "35ae969a-a7db-11ed-afa1-0242ac120002", diff --git a/YoutubeScript.js b/YoutubeScript.js index 654afc0..2044085 100644 --- a/YoutubeScript.js +++ b/YoutubeScript.js @@ -7,6 +7,7 @@ const URL_CONTEXT_M = "https://m.youtube.com"; const URL_CHANNEL_VIDEOS = "/videos"; const URL_CHANNEL_STREAMS = "/streams"; +const URL_CHANNEL_PLAYLISTS = "/playlists"; const URL_SEARCH_SUGGESTIONS = "https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&gs_ri=youtube&ds=yt&q="; const URL_SEARCH = "https://www.youtube.com/youtubei/v1/search"; const URL_BROWSE = "https://www.youtube.com/youtubei/v1/browse"; @@ -1016,6 +1017,29 @@ source.getChannelContents = (url, type, order, filters) => { return new RichGridPager(tab, contextData, useAuth, useAuth); }; +source.getChannelPlaylists = (url) => { + + const targetTab = "Playlists"; + const useAuth = bridge.isLoggedIn() && !!_settings?.authChannels; + if(useAuth) + log("USING AUTH FOR CHANNEL"); + + const initialData = requestInitialData(url + URL_CHANNEL_PLAYLISTS, useAuth, useAuth); + if(!initialData) + throw new ScriptException("No channel data found for: " + url); + const channel = extractChannel_PlatformChannel(initialData, url); + const contextData = { + authorLink: new PlatformAuthorLink(new PlatformID(PLATFORM, channel.id.value, config.id, PLATFORM_CLAIMTYPE), channel.name, channel.url, channel.thumbnail) + }; + const tabs = extractPage_Tabs(initialData, contextData); + + const tab = tabs.find(x=>x.title == targetTab); + if(!tab) + return new PlaylistPager([], false); + + return new RichGridPlaylistPager(tab, contextData, useAuth, useAuth); +} + source.getPeekChannelTypes = () => { return [Type.Feed.Videos, Type.Feed.Mixed]; } @@ -1745,6 +1769,48 @@ class RichGridPager extends VideoPager { return this; } } +class RichGridPlaylistPager extends PlaylistPager { + constructor(tab, context, useMobile = false, useAuth = false) { + super(tab.playlists, tab.videos.length > 0 && !!tab.continuation, context); + this.continuation = tab.continuation; + this.useMobile = useMobile; + this.useAuth = useAuth; + } + + nextPage() { + this.context.page = this.context.page + 1; + if(this.continuation) { + const newData = validateContinuation(()=>requestBrowse({ + continuation: this.continuation.token + }, !!this.useMobile, !!this.useAuth)); + if(newData && newData.length > 0) { + const fakeRichGrid = { + contents: newData + }; + const newItemSection = extractRichGridRenderer_Shelves(fakeRichGrid, this.context); + + if(newItemSection.playlists && newItemSection.playlists.length == 0 && newItemSection.shelves && newItemSection.shelves.length > 0) { + if(IS_TESTING) + console.log("No playlists in root found, checking shelves", newItemSection); + let vids = []; + for(let i = 0; i < newItemSection.shelves.length; i++) { + const shelf = newItemSection.shelves[i]; + vids = vids.concat(shelf.playlists); + } + newItemSection.playlists = vids; + } + + if(newItemSection.playlists) + return new RichGridPager(newItemSection, this.context, this.useMobile, this.useAuth); + } + else + log("Call [RichGridPager.nextPage] continuation gave no appended items, setting empty page with hasMore to false"); + } + this.hasMore = false; + this.results = []; + return this; + } +} class SearchItemSectionVideoPager extends VideoPager { constructor(itemSection) { super(itemSection.videos, itemSection.videos.length > 0 && !!itemSection.continuation); @@ -3037,7 +3103,7 @@ function extractRichGridRenderer_Shelves(richGridRenderer, contextData) { continuation = extractContinuationItemRenderer_Continuation(renderer, contextData); }, itemSectionRenderer(renderer) { - const items = extractItemSectionRenderer_Shelves(renderer); + const items = extractItemSectionRenderer_Shelves(renderer, contextData); if(items.shelves) shelves = shelves.concat(items.shelves); @@ -3069,7 +3135,7 @@ function extractSectionListRenderer_Sections(sectionListRenderer, contextData) { const item = contents[i]; switchKey(item, { itemSectionRenderer(renderer) { - const items = extractItemSectionRenderer_Shelves(renderer); + const items = extractItemSectionRenderer_Shelves(renderer, contextData); if(items.videos.length > 0) videos.push(...items.videos); if(items.channels.length > 0) @@ -3128,6 +3194,11 @@ function extractItemSectionRenderer_Shelves(itemSectionRenderer, contextData) { if(shelf) shelves.push(shelf); }, + gridRenderer(renderer) { + const shelf = extractGridRenderer_Shelf(renderer, contextData); + if(shelf.playlists.length > 0) + playlists.push(...shelf.playlists); + }, default() { const video = switchKeyVideo(item, contextData); if(video) @@ -3144,6 +3215,35 @@ function extractItemSectionRenderer_Shelves(itemSectionRenderer, contextData) { playlists: playlists.filter(x=>x != null) }; } +function extractGridRenderer_Shelf(gridRenderer, contextData) { + const contents = gridRenderer.items; + let shelves = []; + let videos = []; + let channels = []; + let playlists = []; + + contents.forEach((item)=>{ + switchKey(item, { + gridPlaylistRenderer(renderer) { + const playlist = extractPlaylistRenderer_Playlist(renderer, contextData); + if(playlist) + playlists.push(playlist); + }, + default() { + const video = switchKeyVideo(item, contextData); + if(video) + videos.push(video); + } + }); + + }); + + return { + videos: videos.filter(x=>x != null), + channels: channels.filter(x=>x != null), + playlists: playlists.filter(x=>x != null) + }; +} function switchKeyVideos(contents, contextData) { let videos = []; for(let content of contents) { @@ -3396,11 +3496,15 @@ function extractPlaylistRenderer_Playlist(playlistRenderer, contextData) { const author = (contextData && contextData.authorLink) ? contextData.authorLink : extractRuns_AuthorLink(playlistRenderer.shortBylineText?.runs); + let thumbnail = (playlistRenderer.thumbnails && playlistRenderer.thumbnails.length > 0) ? extractThumbnail_BestUrl(playlistRenderer.thumbnails[0]) : null; + if(!thumbnail && playlistRenderer.thumbnail) + thumbnail = extractThumbnail_BestUrl(playlistRenderer.thumbnail); + return new PlatformPlaylist({ id: new PlatformID(PLATFORM, playlistRenderer.playlistId, config.id), author: author, name: extractText_String(playlistRenderer.title), - thumbnail: (playlistRenderer.thumbnails && playlistRenderer.thumbnails.length > 0) ? extractThumbnail_BestUrl(playlistRenderer.thumbnails[0]) : null, + thumbnail: thumbnail, url: URL_PLAYLIST + playlistRenderer.playlistId, videoCount: extractFirstNumber_Integer(extractText_String(playlistRenderer.videoCountText)), }); -- GitLab