diff --git a/src/parser/classes/C4TabbedHeader.ts b/src/parser/classes/C4TabbedHeader.ts index 305cd4edb4..e6417d11c9 100644 --- a/src/parser/classes/C4TabbedHeader.ts +++ b/src/parser/classes/C4TabbedHeader.ts @@ -2,6 +2,7 @@ import { YTNode } from '../helpers.js'; import Parser, { type RawNode } from '../index.js'; import Button from './Button.js'; import ChannelHeaderLinks from './ChannelHeaderLinks.js'; +import ChannelHeaderLinksView from './ChannelHeaderLinksView.js'; import SubscribeButton from './SubscribeButton.js'; import Author from './misc/Author.js'; import Text from './misc/Text.js'; @@ -18,7 +19,7 @@ export default class C4TabbedHeader extends YTNode { videos_count?: Text; sponsor_button?: Button | null; subscribe_button?: SubscribeButton | Button | null; - header_links?: ChannelHeaderLinks | null; + header_links?: ChannelHeaderLinks | ChannelHeaderLinksView | null; channel_handle?: Text; channel_id?: string; @@ -58,7 +59,7 @@ export default class C4TabbedHeader extends YTNode { } if (Reflect.has(data, 'headerLinks')) { - this.header_links = Parser.parseItem(data.headerLinks, ChannelHeaderLinks); + this.header_links = Parser.parseItem(data.headerLinks, [ ChannelHeaderLinks, ChannelHeaderLinksView ]); } if (Reflect.has(data, 'channelHandleText')) { diff --git a/src/parser/classes/ChannelHeaderLinksView.ts b/src/parser/classes/ChannelHeaderLinksView.ts new file mode 100644 index 0000000000..10b5b03ee5 --- /dev/null +++ b/src/parser/classes/ChannelHeaderLinksView.ts @@ -0,0 +1,22 @@ +import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import Text from './misc/Text.js'; + +export default class ChannelHeaderLinksView extends YTNode { + static type = 'ChannelHeaderLinksView'; + + first_link?: Text; + more?: Text; + + constructor(data: RawNode) { + super(); + + if (Reflect.has(data, 'firstLink')) { + this.first_link = Text.fromAttributed(data.firstLink); + } + + if (Reflect.has(data, 'more')) { + this.more = Text.fromAttributed(data.more); + } + } +} \ No newline at end of file diff --git a/src/parser/classes/VideoSecondaryInfo.ts b/src/parser/classes/VideoSecondaryInfo.ts index 5110d048db..be35ed39f1 100644 --- a/src/parser/classes/VideoSecondaryInfo.ts +++ b/src/parser/classes/VideoSecondaryInfo.ts @@ -24,7 +24,7 @@ export default class VideoSecondaryInfo extends YTNode { this.description = new Text(data.description); if (Reflect.has(data, 'attributedDescription')) { - this.description = new Text(this.#convertAttributedDescriptionToRuns(data.attributedDescription)); + this.description = Text.fromAttributed(data.attributedDescription); } this.subscribe_button = Parser.parseItem(data.subscribeButton, [ SubscribeButton, Button ]); @@ -34,72 +34,4 @@ export default class VideoSecondaryInfo extends YTNode { this.default_expanded = data.defaultExpanded; this.description_collapsed_lines = data.descriptionCollapsedLines; } - - #convertAttributedDescriptionToRuns(description: RawNode) { - const runs: { - text: string, - navigationEndpoint?: RawNode, - attachment?: RawNode - }[] = []; - - const content = description.content; - const command_runs = description.commandRuns; - - let last_end_index = 0; - - if (command_runs) { - for (const item of command_runs) { - const length: number = item.length; - const start_index: number = item.startIndex; - - if (start_index > last_end_index) { - runs.push({ - text: content.slice(last_end_index, start_index) - }); - } - - if (Reflect.has(item, 'onTap')) { - let attachment = null; - - if (Reflect.has(description, 'attachmentRuns')) { - const attachment_runs = description.attachmentRuns; - - for (const attatchment_run of attachment_runs) { - if ((attatchment_run.startIndex - 2) == start_index) { - attachment = attatchment_run; - break; - } - } - } - - if (attachment) { - runs.push({ - text: content.slice(start_index, start_index + length), - navigationEndpoint: item.onTap, - attachment - }); - } else { - runs.push({ - text: content.slice(start_index, start_index + length), - navigationEndpoint: item.onTap - }); - } - } - - last_end_index = start_index + length; - } - - if (last_end_index < content.length) { - runs.push({ - text: content.slice(last_end_index) - }); - } - } else { - runs.push({ - text: content - }); - } - - return { runs }; - } } \ No newline at end of file diff --git a/src/parser/classes/misc/Text.ts b/src/parser/classes/misc/Text.ts index 23f14612e3..d90140c8a8 100644 --- a/src/parser/classes/misc/Text.ts +++ b/src/parser/classes/misc/Text.ts @@ -46,6 +46,74 @@ export default class Text { } } + static fromAttributed(data: RawNode): Text { + const runs: { + text: string, + navigationEndpoint?: RawNode, + attachment?: RawNode + }[] = []; + + const content = data.content; + const command_runs = data.commandRuns; + + let last_end_index = 0; + + if (command_runs) { + for (const item of command_runs) { + const length: number = item.length; + const start_index: number = item.startIndex; + + if (start_index > last_end_index) { + runs.push({ + text: content.slice(last_end_index, start_index) + }); + } + + if (Reflect.has(item, 'onTap')) { + let attachment = null; + + if (Reflect.has(data, 'attachmentRuns')) { + const attachment_runs = data.attachmentRuns; + + for (const attatchment_run of attachment_runs) { + if ((attatchment_run.startIndex - 2) == start_index) { + attachment = attatchment_run; + break; + } + } + } + + if (attachment) { + runs.push({ + text: content.slice(start_index, start_index + length), + navigationEndpoint: item.onTap, + attachment + }); + } else { + runs.push({ + text: content.slice(start_index, start_index + length), + navigationEndpoint: item.onTap + }); + } + } + + last_end_index = start_index + length; + } + + if (last_end_index < content.length) { + runs.push({ + text: content.slice(last_end_index) + }); + } + } else { + runs.push({ + text: content + }); + } + + return new Text({ runs }); + } + /** * Converts the text to HTML. * @returns The HTML. diff --git a/src/parser/nodes.ts b/src/parser/nodes.ts index 2901bffd44..750b92290b 100644 --- a/src/parser/nodes.ts +++ b/src/parser/nodes.ts @@ -36,6 +36,7 @@ export { default as ChannelAboutFullMetadata } from './classes/ChannelAboutFullM export { default as ChannelAgeGate } from './classes/ChannelAgeGate.js'; export { default as ChannelFeaturedContent } from './classes/ChannelFeaturedContent.js'; export { default as ChannelHeaderLinks } from './classes/ChannelHeaderLinks.js'; +export { default as ChannelHeaderLinksView } from './classes/ChannelHeaderLinksView.js'; export { default as ChannelMetadata } from './classes/ChannelMetadata.js'; export { default as ChannelMobileHeader } from './classes/ChannelMobileHeader.js'; export { default as ChannelOptions } from './classes/ChannelOptions.js';