From 04d55d04c7ad9a92955ada3c0cd50f7785913043 Mon Sep 17 00:00:00 2001 From: Luan Date: Thu, 18 Jan 2024 14:39:25 -0300 Subject: [PATCH] refactor(Playlist): Ignore `ContinuationItem` nodes from `SectionList#contents` (#579) * feat(PlaylistVideo): Add `style` * refactor(Playlist): Ignore `ContinuationItem` nodes in `SectionList#contents` This should fix some issues regarding the library fetching the wrong continuation or empty continuations (NOTE: This means the solution in 987f506 no longer applies as empty continuations were all in `SectionList#contents`). --- src/parser/classes/PlaylistVideo.ts | 5 ++++ src/parser/youtube/Playlist.ts | 39 ++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/parser/classes/PlaylistVideo.ts b/src/parser/classes/PlaylistVideo.ts index 6fd7cd4c..08939379 100644 --- a/src/parser/classes/PlaylistVideo.ts +++ b/src/parser/classes/PlaylistVideo.ts @@ -23,6 +23,7 @@ export default class PlaylistVideo extends YTNode { upcoming?: Date; video_info: Text; accessibility_label?: string; + style?: string; duration: { text: string; @@ -44,6 +45,10 @@ export default class PlaylistVideo extends YTNode { this.video_info = new Text(data.videoInfo); this.accessibility_label = data.title.accessibility.accessibilityData.label; + if (Reflect.has(data, 'style')) { + this.style = data.style; + } + const upcoming = data.upcomingEventData && Number(`${data.upcomingEventData.startTime}000`); if (upcoming) { this.upcoming = new Date(upcoming); diff --git a/src/parser/youtube/Playlist.ts b/src/parser/youtube/Playlist.ts index f4b58d62..6c6868ef 100644 --- a/src/parser/youtube/Playlist.ts +++ b/src/parser/youtube/Playlist.ts @@ -10,9 +10,12 @@ import PlaylistSidebarSecondaryInfo from '../classes/PlaylistSidebarSecondaryInf import PlaylistVideoThumbnail from '../classes/PlaylistVideoThumbnail.js'; import VideoOwner from '../classes/VideoOwner.js'; import Alert from '../classes/Alert.js'; +import ContinuationItem from '../classes/ContinuationItem.js'; +import PlaylistVideo from '../classes/PlaylistVideo.js'; +import SectionList from '../classes/SectionList.js'; import { InnertubeError } from '../../utils/Utils.js'; -import type { ObservedArray } from '../helpers.js'; +import { observe, type ObservedArray } from '../helpers.js'; import type Actions from '../../core/Actions.js'; import type { ApiResponse } from '../../core/Actions.js'; @@ -64,8 +67,38 @@ export default class Playlist extends Feed { return primary_info.stats[index]?.toString() || 'N/A'; } - get items() { - return this.videos; + get items(): ObservedArray { + return observe(this.videos.as(PlaylistVideo).filter((video) => video.style !== 'PLAYLIST_VIDEO_RENDERER_STYLE_RECOMMENDED_VIDEO')); + } + + get has_continuation() { + const section_list = this.memo.getType(SectionList).first(); + + if (!section_list) + return super.has_continuation; + + return !!this.memo.getType(ContinuationItem).find((node) => !section_list.contents.includes(node)); + } + + async getContinuationData(): Promise { + const section_list = this.memo.getType(SectionList).first(); + + /** + * No section list means there can't be additional continuation nodes here, + * so no need to check. + */ + if (!section_list) + return await super.getContinuationData(); + + const playlist_contents_continuation = this.memo.getType(ContinuationItem) + .find((node) => !section_list.contents.includes(node)); + + if (!playlist_contents_continuation) + throw new InnertubeError('There are no continuations.'); + + const response = await playlist_contents_continuation.endpoint.call(this.actions, { parse: true }); + + return response; } async getContinuation(): Promise {