diff --git a/src/core/Music.ts b/src/core/Music.ts index 629140a7..41a50b67 100644 --- a/src/core/Music.ts +++ b/src/core/Music.ts @@ -20,7 +20,6 @@ import SearchSuggestionsSection from '../parser/classes/SearchSuggestionsSection import SectionList from '../parser/classes/SectionList.js'; import Tab from '../parser/classes/Tab.js'; -import { observe } from '../parser/helpers.js'; import Proto from '../proto/index.js'; import { generateRandomString, InnertubeError, throwIfMissing } from '../utils/Utils.js'; @@ -327,7 +326,7 @@ class Music { throw new InnertubeError('Unexpected response', page); if (page.contents.item().key('type').string() === 'Message') - throw new InnertubeError(page.contents.item().as(Message).text, video_id); + throw new InnertubeError(page.contents.item().as(Message).text.toString(), video_id); const section_list = page.contents.item().as(SectionList).contents; @@ -357,12 +356,12 @@ class Music { client: 'YTMUSIC' }); - const search_suggestions_section = response.contents_memo?.getType(SearchSuggestionsSection)?.[0]; + if (!response.contents_memo) + throw new InnertubeError('Unexpected response', response); - if (!search_suggestions_section?.contents.is_array) - return observe([] as YTNode[]); + const search_suggestions_section = response.contents_memo.getType(SearchSuggestionsSection).first(); - return search_suggestions_section?.contents.array(); + return search_suggestions_section.contents; } } diff --git a/src/parser/classes/AccountChannel.ts b/src/parser/classes/AccountChannel.ts index 6c3af847..50dc2695 100644 --- a/src/parser/classes/AccountChannel.ts +++ b/src/parser/classes/AccountChannel.ts @@ -3,7 +3,7 @@ import NavigationEndpoint from './NavigationEndpoint.js'; import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; -class AccountChannel extends YTNode { +export default class AccountChannel extends YTNode { static type = 'AccountChannel'; title: Text; @@ -14,6 +14,4 @@ class AccountChannel extends YTNode { this.title = new Text(data.title); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); } -} - -export default AccountChannel; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/AccountItemSection.ts b/src/parser/classes/AccountItemSection.ts index eb64f8da..c614df6c 100644 --- a/src/parser/classes/AccountItemSection.ts +++ b/src/parser/classes/AccountItemSection.ts @@ -1,14 +1,16 @@ import Parser from '../index.js'; - +import AccountItemSectionHeader from './AccountItemSectionHeader.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; import Text from './misc/Text.js'; import Thumbnail from './misc/Thumbnail.js'; -import NavigationEndpoint from './NavigationEndpoint.js'; -import AccountItemSectionHeader from './AccountItemSectionHeader.js'; -import { YTNode } from '../helpers.js'; +import { YTNode, observe, type ObservedArray } from '../helpers.js'; import type { RawNode } from '../index.js'; -class AccountItem { +/** + * Not a real renderer but we treat it as one to keep things organized. + */ +export class AccountItem extends YTNode { static type = 'AccountItem'; account_name: Text; @@ -20,27 +22,26 @@ class AccountItem { account_byline: Text; constructor(data: RawNode) { + super(); this.account_name = new Text(data.accountName); this.account_photo = Thumbnail.fromResponse(data.accountPhoto); - this.is_selected = data.isSelected; - this.is_disabled = data.isDisabled; - this.has_channel = data.hasChannel; + this.is_selected = !!data.isSelected; + this.is_disabled = !!data.isDisabled; + this.has_channel = !!data.hasChannel; this.endpoint = new NavigationEndpoint(data.serviceEndpoint); this.account_byline = new Text(data.accountByline); } } -class AccountItemSection extends YTNode { +export default class AccountItemSection extends YTNode { static type = 'AccountItemSection'; - contents; - header; + contents: ObservedArray; + header: AccountItemSectionHeader | null; constructor(data: RawNode) { super(); - this.contents = data.contents.map((ac: any) => new AccountItem(ac.accountItem)); + this.contents = observe(data.contents.map((ac: RawNode) => new AccountItem(ac.accountItem))); this.header = Parser.parseItem(data.header, AccountItemSectionHeader); } -} - -export default AccountItemSection; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/AccountItemSectionHeader.ts b/src/parser/classes/AccountItemSectionHeader.ts index 1653392a..7e6fa325 100644 --- a/src/parser/classes/AccountItemSectionHeader.ts +++ b/src/parser/classes/AccountItemSectionHeader.ts @@ -1,7 +1,8 @@ import Text from './misc/Text.js'; import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; -class AccountItemSectionHeader extends YTNode { + +export default class AccountItemSectionHeader extends YTNode { static type = 'AccountItemSectionHeader'; title: Text; @@ -10,6 +11,4 @@ class AccountItemSectionHeader extends YTNode { super(); this.title = new Text(data.title); } -} - -export default AccountItemSectionHeader; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/AccountSectionList.ts b/src/parser/classes/AccountSectionList.ts index 2c5759d7..b42c8211 100644 --- a/src/parser/classes/AccountSectionList.ts +++ b/src/parser/classes/AccountSectionList.ts @@ -4,7 +4,8 @@ import AccountItemSection from './AccountItemSection.js'; import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; -class AccountSectionList extends YTNode { + +export default class AccountSectionList extends YTNode { static type = 'AccountSectionList'; contents; @@ -15,6 +16,4 @@ class AccountSectionList extends YTNode { this.contents = Parser.parseItem(data.contents[0], AccountItemSection); this.footers = Parser.parseItem(data.footers[0], AccountChannel); } -} - -export default AccountSectionList; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/Alert.ts b/src/parser/classes/Alert.ts index e080d24c..cd1d8e99 100644 --- a/src/parser/classes/Alert.ts +++ b/src/parser/classes/Alert.ts @@ -1,7 +1,8 @@ import Text from './misc/Text.js'; import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; -class Alert extends YTNode { + +export default class Alert extends YTNode { static type = 'Alert'; text: Text; @@ -12,6 +13,4 @@ class Alert extends YTNode { this.text = new Text(data.text); this.alert_type = data.type; } -} - -export default Alert; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/AudioOnlyPlayability.ts b/src/parser/classes/AudioOnlyPlayability.ts index f5f6daaa..1ccea68e 100644 --- a/src/parser/classes/AudioOnlyPlayability.ts +++ b/src/parser/classes/AudioOnlyPlayability.ts @@ -1,6 +1,7 @@ import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; -class AudioOnlyPlayability extends YTNode { + +export default class AudioOnlyPlayability extends YTNode { static type = 'AudioOnlyPlayability'; audio_only_availability: string; @@ -9,6 +10,4 @@ class AudioOnlyPlayability extends YTNode { super(); this.audio_only_availability = data.audioOnlyAvailability; } -} - -export default AudioOnlyPlayability; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/AutomixPreviewVideo.ts b/src/parser/classes/AutomixPreviewVideo.ts index 0759f3fa..a47d4008 100644 --- a/src/parser/classes/AutomixPreviewVideo.ts +++ b/src/parser/classes/AutomixPreviewVideo.ts @@ -1,7 +1,8 @@ import { YTNode } from '../helpers.js'; import NavigationEndpoint from './NavigationEndpoint.js'; import type { RawNode } from '../index.js'; -class AutomixPreviewVideo extends YTNode { + +export default class AutomixPreviewVideo extends YTNode { static type = 'AutomixPreviewVideo'; playlist_video?: { endpoint: NavigationEndpoint }; @@ -14,6 +15,4 @@ class AutomixPreviewVideo extends YTNode { }; } } -} - -export default AutomixPreviewVideo; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/BackstageImage.ts b/src/parser/classes/BackstageImage.ts index af11137e..bbb54a5a 100644 --- a/src/parser/classes/BackstageImage.ts +++ b/src/parser/classes/BackstageImage.ts @@ -1,18 +1,17 @@ import Thumbnail from './misc/Thumbnail.js'; import NavigationEndpoint from './NavigationEndpoint.js'; import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; -class BackstageImage extends YTNode { +export default class BackstageImage extends YTNode { static type = 'BackstageImage'; image: Thumbnail[]; endpoint: NavigationEndpoint; - constructor(data: any) { + constructor(data: RawNode) { super(); this.image = Thumbnail.fromResponse(data.image); this.endpoint = new NavigationEndpoint(data.command); } -} - -export default BackstageImage; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/BackstagePost.ts b/src/parser/classes/BackstagePost.ts index 0ccd3518..e556e59c 100644 --- a/src/parser/classes/BackstagePost.ts +++ b/src/parser/classes/BackstagePost.ts @@ -1,13 +1,12 @@ -import Parser from '../index.js'; -import Author from './misc/Author.js'; -import Text from './misc/Text.js'; +import { YTNode } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; import NavigationEndpoint from './NavigationEndpoint.js'; import CommentActionButtons from './comments/CommentActionButtons.js'; import Menu from './menus/Menu.js'; +import Author from './misc/Author.js'; +import Text from './misc/Text.js'; -import { YTNode } from '../helpers.js'; - -class BackstagePost extends YTNode { +export default class BackstagePost extends YTNode { static type = 'BackstagePost'; id: string; @@ -18,13 +17,13 @@ class BackstagePost extends YTNode { vote_status?: string; vote_count?: Text; menu?: Menu | null; - action_buttons; - vote_button; + action_buttons?: CommentActionButtons | null; + vote_button?: CommentActionButtons | null; surface: string; endpoint?: NavigationEndpoint; attachment; - constructor(data: any) { + constructor(data: RawNode) { super(); this.id = data.postId; @@ -36,40 +35,38 @@ class BackstagePost extends YTNode { this.content = new Text(data.contentText); this.published = new Text(data.publishedTimeText); - if (data.pollStatus) { + if (Reflect.has(data, 'pollStatus')) { this.poll_status = data.pollStatus; } - if (data.voteStatus) { + if (Reflect.has(data, 'voteStatus')) { this.vote_status = data.voteStatus; } - if (data.voteCount) { + if (Reflect.has(data, 'voteCount')) { this.vote_count = new Text(data.voteCount); } - if (data.actionMenu) { + if (Reflect.has(data, 'actionMenu')) { this.menu = Parser.parseItem(data.actionMenu, Menu); } - if (data.actionButtons) { + if (Reflect.has(data, 'actionButtons')) { this.action_buttons = Parser.parseItem(data.actionButtons, CommentActionButtons); } - if (data.voteButton) { + if (Reflect.has(data, 'voteButton')) { this.vote_button = Parser.parseItem(data.voteButton, CommentActionButtons); } - if (data.navigationEndpoint) { + if (Reflect.has(data, 'navigationEndpoint')) { this.endpoint = new NavigationEndpoint(data.navigationEndpoint); } - if (data.backstageAttachment) { + if (Reflect.has(data, 'backstageAttachment')) { this.attachment = Parser.parseItem(data.backstageAttachment); } this.surface = data.surface; } -} - -export default BackstagePost; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/BackstagePostThread.ts b/src/parser/classes/BackstagePostThread.ts index 77e17a19..189ceb1c 100644 --- a/src/parser/classes/BackstagePostThread.ts +++ b/src/parser/classes/BackstagePostThread.ts @@ -1,15 +1,13 @@ -import Parser from '../index.js'; +import Parser, { type RawNode } from '../index.js'; import { YTNode } from '../helpers.js'; -class BackstagePostThread extends YTNode { +export default class BackstagePostThread extends YTNode { static type = 'BackstagePostThread'; - post; + post: YTNode; - constructor(data: any) { + constructor(data: RawNode) { super(); this.post = Parser.parseItem(data.post); } -} - -export default BackstagePostThread; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/BrowseFeedActions.ts b/src/parser/classes/BrowseFeedActions.ts index b9e47eb0..432222e9 100644 --- a/src/parser/classes/BrowseFeedActions.ts +++ b/src/parser/classes/BrowseFeedActions.ts @@ -1,15 +1,13 @@ -import Parser from '../index.js'; -import { YTNode } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; +import { type ObservedArray, YTNode } from '../helpers.js'; -class BrowseFeedActions extends YTNode { +export default class BrowseFeedActions extends YTNode { static type = 'BrowseFeedActions'; - contents; + contents: ObservedArray; - constructor(data: any) { + constructor(data: RawNode) { super(); this.contents = Parser.parseArray(data.contents); } -} - -export default BrowseFeedActions; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/BrowserMediaSession.ts b/src/parser/classes/BrowserMediaSession.ts index f62fd2ed..23f2a2c0 100644 --- a/src/parser/classes/BrowserMediaSession.ts +++ b/src/parser/classes/BrowserMediaSession.ts @@ -1,18 +1,17 @@ import Text from './misc/Text.js'; import Thumbnail from './misc/Thumbnail.js'; import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; -class BrowserMediaSession extends YTNode { +export default class BrowserMediaSession extends YTNode { static type = 'BrowserMediaSession'; - album; - thumbnails; + album: Text; + thumbnails: Thumbnail[]; - constructor (data: any) { + constructor (data: RawNode) { super(); this.album = new Text(data.album); this.thumbnails = Thumbnail.fromResponse(data.thumbnailDetails); } -} - -export default BrowserMediaSession; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/Button.ts b/src/parser/classes/Button.ts index 6971e080..3d83207a 100644 --- a/src/parser/classes/Button.ts +++ b/src/parser/classes/Button.ts @@ -1,6 +1,5 @@ import Text from './misc/Text.js'; import NavigationEndpoint from './NavigationEndpoint.js'; - import { YTNode } from '../helpers.js'; import type { RawNode } from '../index.js'; @@ -8,31 +7,29 @@ export default class Button extends YTNode { static type = 'Button'; text?: string; - label?: string; tooltip?: string; icon_type?: string; is_disabled?: boolean; - endpoint: NavigationEndpoint; constructor(data: RawNode) { super(); - if (data.text) { + if (Reflect.has(data, 'text')) { this.text = new Text(data.text).toString(); } - if (data.accessibility?.label) { - this.label = data.accessibility?.label; + if (Reflect.has(data, 'accessibility') && Reflect.has(data.accessibility, 'label')) { + this.label = data.accessibility.label; } - if (data.tooltip) { + if (Reflect.has(data, 'tooltip')) { this.tooltip = data.tooltip; } - if (data.icon?.iconType) { - this.icon_type = data.icon?.iconType; + if (Reflect.has(data, 'icon') && Reflect.has(data.icon, 'iconType')) { + this.icon_type = data.icon.iconType; } if (Reflect.has(data, 'isDisabled')) { diff --git a/src/parser/classes/C4TabbedHeader.ts b/src/parser/classes/C4TabbedHeader.ts index 2c6c5be4..305cd4ed 100644 --- a/src/parser/classes/C4TabbedHeader.ts +++ b/src/parser/classes/C4TabbedHeader.ts @@ -1,15 +1,13 @@ -import Parser from '../index.js'; +import { YTNode } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; +import Button from './Button.js'; +import ChannelHeaderLinks from './ChannelHeaderLinks.js'; +import SubscribeButton from './SubscribeButton.js'; import Author from './misc/Author.js'; import Text from './misc/Text.js'; import Thumbnail from './misc/Thumbnail.js'; -import Button from './Button.js'; -import ChannelHeaderLinks from './ChannelHeaderLinks.js'; -import SubscribeButton from './SubscribeButton.js'; - -import { YTNode } from '../helpers.js'; - -class C4TabbedHeader extends YTNode { +export default class C4TabbedHeader extends YTNode { static type = 'C4TabbedHeader'; author: Author; @@ -24,53 +22,51 @@ class C4TabbedHeader extends YTNode { channel_handle?: Text; channel_id?: string; - constructor(data: any) { + constructor(data: RawNode) { super(); this.author = new Author({ simpleText: data.title, navigationEndpoint: data.navigationEndpoint }, data.badges, data.avatar); - if (data.banner) { + if (Reflect.has(data, 'banner')) { this.banner = Thumbnail.fromResponse(data.banner); } - if (data.tv_banner) { + if (Reflect.has(data, 'tv_banner')) { this.tv_banner = Thumbnail.fromResponse(data.tvBanner); } - if (data.mobile_banner) { + if (Reflect.has(data, 'mobile_banner')) { this.mobile_banner = Thumbnail.fromResponse(data.mobileBanner); } - if (data.subscriberCountText) { + if (Reflect.has(data, 'subscriberCountText')) { this.subscribers = new Text(data.subscriberCountText); } - if (data.videosCountText) { + if (Reflect.has(data, 'videosCountText')) { this.videos_count = new Text(data.videosCountText); } - if (data.sponsorButton) { + if (Reflect.has(data, 'sponsorButton')) { this.sponsor_button = Parser.parseItem(data.sponsorButton, Button); } - if (data.subscribeButton) { + if (Reflect.has(data, 'subscribeButton')) { this.subscribe_button = Parser.parseItem(data.subscribeButton, [ SubscribeButton, Button ]); } - if (data.headerLinks) { + if (Reflect.has(data, 'headerLinks')) { this.header_links = Parser.parseItem(data.headerLinks, ChannelHeaderLinks); } - if (data.channelHandleText) { + if (Reflect.has(data, 'channelHandleText')) { this.channel_handle = new Text(data.channelHandleText); } - if (data.channelId) { + if (Reflect.has(data, 'channelId')) { this.channel_id = data.channelId; } } -} - -export default C4TabbedHeader; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/CallToActionButton.ts b/src/parser/classes/CallToActionButton.ts index a803b5ef..106f9aed 100644 --- a/src/parser/classes/CallToActionButton.ts +++ b/src/parser/classes/CallToActionButton.ts @@ -1,19 +1,18 @@ import Text from './misc/Text.js'; import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; -class CallToActionButton extends YTNode { +export default class CallToActionButton extends YTNode { static type = 'CallToActionButton'; label: Text; icon_type: string; style: string; - constructor(data: any) { + constructor(data: RawNode) { super(); this.label = new Text(data.label); this.icon_type = data.icon.iconType; this.style = data.style; } -} - -export default CallToActionButton; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/Card.ts b/src/parser/classes/Card.ts index 872476d5..f49dc03c 100644 --- a/src/parser/classes/Card.ts +++ b/src/parser/classes/Card.ts @@ -1,13 +1,13 @@ -import Parser from '../index.js'; +import Parser, { type RawNode } from '../index.js'; import { YTNode } from '../helpers.js'; -class Card extends YTNode { +export default class Card extends YTNode { static type = 'Card'; - teaser; - content; - card_id: string | null; - feature: string | null; + teaser: YTNode; + content: YTNode; + card_id?: string; + feature?: string; cue_ranges: { start_card_active_ms: string; @@ -16,12 +16,18 @@ class Card extends YTNode { icon_after_teaser_ms: string; }[]; - constructor(data: any) { + constructor(data: RawNode) { super(); this.teaser = Parser.parseItem(data.teaser); this.content = Parser.parseItem(data.content); - this.card_id = data.cardId || null; - this.feature = data.feature || null; + + if (Reflect.has(data, 'cardId')) { + this.card_id = data.cardId; + } + + if (Reflect.has(data, 'feature')) { + this.feature = data.feature; + } this.cue_ranges = data.cueRanges.map((cr: any) => ({ start_card_active_ms: cr.startCardActiveMs, @@ -30,6 +36,4 @@ class Card extends YTNode { icon_after_teaser_ms: cr.iconAfterTeaserMs })); } -} - -export default Card; +} \ No newline at end of file diff --git a/src/parser/classes/CardCollection.ts b/src/parser/classes/CardCollection.ts index 5f60d81d..ba57812a 100644 --- a/src/parser/classes/CardCollection.ts +++ b/src/parser/classes/CardCollection.ts @@ -1,20 +1,18 @@ -import Parser from '../index.js'; +import { YTNode, type ObservedArray } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; import Text from './misc/Text.js'; -import { YTNode } from '../helpers.js'; -class CardCollection extends YTNode { +export default class CardCollection extends YTNode { static type = 'CardCollection'; - cards; + cards: ObservedArray; header: Text; allow_teaser_dismiss: boolean; - constructor(data: any) { + constructor(data: RawNode) { super(); this.cards = Parser.parseArray(data.cards); this.header = new Text(data.headerText); this.allow_teaser_dismiss = data.allowTeaserDismiss; } -} - -export default CardCollection; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/CarouselHeader.ts b/src/parser/classes/CarouselHeader.ts index fb3cde85..d3e617b1 100644 --- a/src/parser/classes/CarouselHeader.ts +++ b/src/parser/classes/CarouselHeader.ts @@ -1,15 +1,13 @@ -import Parser from '../index.js'; -import { YTNode } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; +import { type ObservedArray, YTNode } from '../helpers.js'; -class CarouselHeader extends YTNode { +export default class CarouselHeader extends YTNode { static type = 'CarouselHeader'; - contents: YTNode[]; + contents: ObservedArray; - constructor(data: any) { + constructor(data: RawNode) { super(); this.contents = Parser.parseArray(data.contents); } -} - -export default CarouselHeader; \ No newline at end of file +} \ No newline at end of file diff --git a/src/parser/classes/CarouselItem.ts b/src/parser/classes/CarouselItem.ts index 58810e79..871711a1 100644 --- a/src/parser/classes/CarouselItem.ts +++ b/src/parser/classes/CarouselItem.ts @@ -1,18 +1,17 @@ -import Parser from '../index.js'; -import { YTNode } from '../helpers.js'; - +import Parser, { type RawNode } from '../index.js'; +import { type ObservedArray, YTNode } from '../helpers.js'; import Thumbnail from './misc/Thumbnail.js'; -class CarouselItem extends YTNode { +export default class CarouselItem extends YTNode { static type = 'CarouselItem'; - items: YTNode[]; + items: ObservedArray; background_color: string; layout_style: string; pagination_thumbnails: Thumbnail[]; paginator_alignment: string; - constructor (data: any) { + constructor (data: RawNode) { super(); this.items = Parser.parseArray(data.carouselItems); this.background_color = data.backgroundColor; @@ -20,6 +19,9 @@ class CarouselItem extends YTNode { this.pagination_thumbnails = Thumbnail.fromResponse(data.paginationThumbnails); this.paginator_alignment = data.paginatorAlignment; } -} -export default CarouselItem; \ No newline at end of file + // XXX: For consistency. + get contents() { + return this.items; + } +} \ No newline at end of file diff --git a/src/parser/classes/Channel.ts b/src/parser/classes/Channel.ts index 5ce7ee58..1c08d869 100644 --- a/src/parser/classes/Channel.ts +++ b/src/parser/classes/Channel.ts @@ -1,28 +1,25 @@ -import Parser from '../index.js'; - -import Text from './misc/Text.js'; -import Author from './misc/Author.js'; -import NavigationEndpoint from './NavigationEndpoint.js'; - -import SubscribeButton from './SubscribeButton.js'; -import Button from './Button.js'; - import { YTNode } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; +import Button from './Button.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; +import SubscribeButton from './SubscribeButton.js'; +import Author from './misc/Author.js'; +import Text from './misc/Text.js'; -class Channel extends YTNode { +export default class Channel extends YTNode { static type = 'Channel'; id: string; author: Author; - subscribers: Text; - videos: Text; + subscriber_count: Text; + video_count: Text; long_byline: Text; short_byline: Text; endpoint: NavigationEndpoint; subscribe_button: SubscribeButton | Button | null; description_snippet: Text; - constructor(data: any) { + constructor(data: RawNode) { super(); this.id = data.channelId; @@ -31,15 +28,31 @@ class Channel extends YTNode { navigationEndpoint: data.navigationEndpoint }, data.ownerBadges, data.thumbnail); - // TODO: subscriberCountText is now the channel's handle and videoCountText is the subscriber count. Why haven't they renamed the properties? - this.subscribers = new Text(data.subscriberCountText); - this.videos = new Text(data.videoCountText); + // XXX: `subscriberCountText` is now the channel's handle and `videoCountText` is the subscriber count. + this.subscriber_count = new Text(data.subscriberCountText); + this.video_count = new Text(data.videoCountText); this.long_byline = new Text(data.longBylineText); this.short_byline = new Text(data.shortBylineText); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.subscribe_button = Parser.parseItem(data.subscribeButton, [ SubscribeButton, Button ]); this.description_snippet = new Text(data.descriptionSnippet); } -} -export default Channel; + /** + * @deprecated + * This will be removed in a future release. + * Please use {@link Channel.subscriber_count} instead. + */ + get subscribers(): Text { + return this.subscriber_count; + } + + /** + * @deprecated + * This will be removed in a future release. + * Please use {@link Channel.video_count} instead. + */ + get videos(): Text { + return this.video_count; + } +} \ No newline at end of file diff --git a/src/parser/classes/ChannelAboutFullMetadata.ts b/src/parser/classes/ChannelAboutFullMetadata.ts index d6ef6687..c6de7523 100644 --- a/src/parser/classes/ChannelAboutFullMetadata.ts +++ b/src/parser/classes/ChannelAboutFullMetadata.ts @@ -1,14 +1,11 @@ -import Parser from '../index.js'; - +import { YTNode, type ObservedArray } from '../helpers.js'; +import Parser, { type RawNode } from '../index.js'; +import Button from './Button.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; import Text from './misc/Text.js'; import Thumbnail from './misc/Thumbnail.js'; -import NavigationEndpoint from './NavigationEndpoint.js'; -import Button from './Button.js'; - -import { YTNode } from '../helpers.js'; - -class ChannelAboutFullMetadata extends YTNode { +export default class ChannelAboutFullMetadata extends YTNode { static type = 'ChannelAboutFullMetadata'; id: string; @@ -22,15 +19,15 @@ class ChannelAboutFullMetadata extends YTNode { title: Text; }[]; - views: Text; - joined: Text; + view_count: Text; + joined_date: Text; description: Text; email_reveal: NavigationEndpoint; can_reveal_email: boolean; country: Text; - buttons: Button[]; + buttons: ObservedArray