diff --git a/src/parser/classes/ButtonView.ts b/src/parser/classes/ButtonView.ts new file mode 100644 index 00000000..b6c9bbd1 --- /dev/null +++ b/src/parser/classes/ButtonView.ts @@ -0,0 +1,28 @@ +import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; + +export default class ButtonView extends YTNode { + static type = 'ButtonView'; + + icon_name: string; + title: string; + accessibility_text: string; + style: string; + is_full_width: boolean; + type: string; + button_size: string; + on_tap: NavigationEndpoint; + + constructor(data: RawNode) { + super(); + this.icon_name = data.iconName; + this.title = data.title; + this.accessibility_text = data.accessibilityText; + this.style = data.style; + this.is_full_width = data.isFullWidth; + this.type = data.type; + this.button_size = data.buttonSize; + this.on_tap = new NavigationEndpoint(data.onTap); + } +} \ No newline at end of file diff --git a/src/parser/classes/ContentMetadataView.ts b/src/parser/classes/ContentMetadataView.ts new file mode 100644 index 00000000..c1da74ac --- /dev/null +++ b/src/parser/classes/ContentMetadataView.ts @@ -0,0 +1,26 @@ +import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import { Text } from '../misc.js'; + +export type MetadataRow = { + metadata_parts: { + text: Text; + }[]; +}; + +export default class ContentMetadataView extends YTNode { + static type = 'ContentMetadataView'; + + metadata_rows: MetadataRow[]; + delimiter: string; + + constructor(data: RawNode) { + super(); + this.metadata_rows = data.metadataRows.map((row: RawNode) => ({ + metadata_parts: row.metadataParts.map((part: RawNode) => ({ + text: Text.fromAttributed(part.text) + })) + })); + this.delimiter = data.delimiter; + } +} \ No newline at end of file diff --git a/src/parser/classes/FlexibleActionsView.ts b/src/parser/classes/FlexibleActionsView.ts new file mode 100644 index 00000000..078df9f7 --- /dev/null +++ b/src/parser/classes/FlexibleActionsView.ts @@ -0,0 +1,22 @@ +import { type ObservedArray, YTNode } from '../helpers.js'; +import { Parser, type RawNode } from '../index.js'; +import ButtonView from './ButtonView.js'; + +export type ActionRow = { + actions: ObservedArray; +}; + +export default class FlexibleActionsView extends YTNode { + static type = 'FlexibleActionsView'; + + actions_rows: ActionRow[]; + style: string; + + constructor(data: RawNode) { + super(); + this.actions_rows = data.actionsRows.map((row: RawNode) => ({ + actions: Parser.parseArray(row.actions, ButtonView) + })); + this.style = data.style; + } +} \ No newline at end of file diff --git a/src/parser/classes/PageHeaderView.ts b/src/parser/classes/PageHeaderView.ts index 83c6af59..dc74ff6d 100644 --- a/src/parser/classes/PageHeaderView.ts +++ b/src/parser/classes/PageHeaderView.ts @@ -1,17 +1,23 @@ import { YTNode } from '../helpers.js'; import { Parser, type RawNode } from '../index.js'; +import ContentMetadataView from './ContentMetadataView.js'; import ContentPreviewImageView from './ContentPreviewImageView.js'; import DynamicTextView from './DynamicTextView.js'; +import FlexibleActionsView from './FlexibleActionsView.js'; export default class PageHeaderView extends YTNode { static type = 'PageHeaderView'; - image: ContentPreviewImageView | null; title: DynamicTextView | null; + image: ContentPreviewImageView | null; + metadata: YTNode | null; + actions: YTNode | null; constructor(data: RawNode) { super(); - this.image = Parser.parseItem(data.image, ContentPreviewImageView); this.title = Parser.parseItem(data.title, DynamicTextView); + this.image = Parser.parseItem(data.image, ContentPreviewImageView); + this.metadata = Parser.parseItem(data.metadata, ContentMetadataView); + this.actions = Parser.parseItem(data.actions, FlexibleActionsView); } } \ No newline at end of file diff --git a/src/parser/nodes.ts b/src/parser/nodes.ts index 41725da0..9a1cf53e 100644 --- a/src/parser/nodes.ts +++ b/src/parser/nodes.ts @@ -28,6 +28,7 @@ export { default as BackstagePostThread } from './classes/BackstagePostThread.js export { default as BrowseFeedActions } from './classes/BrowseFeedActions.js'; export { default as BrowserMediaSession } from './classes/BrowserMediaSession.js'; export { default as Button } from './classes/Button.js'; +export { default as ButtonView } from './classes/ButtonView.js'; export { default as C4TabbedHeader } from './classes/C4TabbedHeader.js'; export { default as CallToActionButton } from './classes/CallToActionButton.js'; export { default as Card } from './classes/Card.js'; @@ -86,6 +87,7 @@ export { default as CompactPlaylist } from './classes/CompactPlaylist.js'; export { default as CompactStation } from './classes/CompactStation.js'; export { default as CompactVideo } from './classes/CompactVideo.js'; export { default as ConfirmDialog } from './classes/ConfirmDialog.js'; +export { default as ContentMetadataView } from './classes/ContentMetadataView.js'; export { default as ContentPreviewImageView } from './classes/ContentPreviewImageView.js'; export { default as ContinuationItem } from './classes/ContinuationItem.js'; export { default as ConversationBar } from './classes/ConversationBar.js'; @@ -118,6 +120,7 @@ export { default as FancyDismissibleDialog } from './classes/FancyDismissibleDia export { default as FeedFilterChipBar } from './classes/FeedFilterChipBar.js'; export { default as FeedNudge } from './classes/FeedNudge.js'; export { default as FeedTabbedHeader } from './classes/FeedTabbedHeader.js'; +export { default as FlexibleActionsView } from './classes/FlexibleActionsView.js'; export { default as GameCard } from './classes/GameCard.js'; export { default as GameDetails } from './classes/GameDetails.js'; export { default as Grid } from './classes/Grid.js'; diff --git a/src/parser/youtube/Library.ts b/src/parser/youtube/Library.ts index 93540c8b..82d66dc8 100644 --- a/src/parser/youtube/Library.ts +++ b/src/parser/youtube/Library.ts @@ -8,18 +8,12 @@ import Menu from '../classes/menus/Menu.js'; import Shelf from '../classes/Shelf.js'; import Button from '../classes/Button.js'; -import ProfileColumnStats from '../classes/ProfileColumnStats.js'; -import ProfileColumnUserInfo from '../classes/ProfileColumnUserInfo.js'; - import type { IBrowseResponse } from '../types/ParsedResponse.js'; import type { ApiResponse } from '../../core/Actions.js'; +import { PageHeader } from '../nodes.js'; class Library extends Feed { - profile: { - stats?: ProfileColumnStats; - user_info?: ProfileColumnUserInfo; - }; - + header: PageHeader | null; sections; constructor(actions: Actions, data: ApiResponse | IBrowseResponse) { @@ -28,10 +22,7 @@ class Library extends Feed { if (!this.page.contents_memo) throw new InnertubeError('Page contents not found'); - const stats = this.page.contents_memo.getType(ProfileColumnStats).first(); - const user_info = this.page.contents_memo.getType(ProfileColumnUserInfo).first(); - - this.profile = { stats, user_info }; + this.header = this.memo.getType(PageHeader).first(); const shelves = this.page.contents_memo.getType(Shelf);