From f4ce4d2f746f44dc9ad6381d89ba0e179a8ec98b Mon Sep 17 00:00:00 2001 From: LuanRT Date: Thu, 25 Aug 2022 01:43:05 -0300 Subject: [PATCH] feat: add account info parsers --- src/core/AccountManager.ts | 17 ++----- src/parser/classes/AccountChannel.ts | 18 ++++++++ src/parser/classes/AccountItemSection.ts | 45 +++++++++++++++++++ .../classes/AccountItemSectionHeader.ts | 15 +++++++ src/parser/classes/AccountSectionList.ts | 20 +++++++++ src/parser/map.ts | 8 ++++ src/parser/youtube/AccountInfo.ts | 28 ++++++++++++ 7 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 src/parser/classes/AccountChannel.ts create mode 100644 src/parser/classes/AccountItemSection.ts create mode 100644 src/parser/classes/AccountItemSectionHeader.ts create mode 100644 src/parser/classes/AccountSectionList.ts create mode 100644 src/parser/youtube/AccountInfo.ts diff --git a/src/core/AccountManager.ts b/src/core/AccountManager.ts index 8f3abcc0..0c9e81ba 100644 --- a/src/core/AccountManager.ts +++ b/src/core/AccountManager.ts @@ -5,6 +5,7 @@ import { throwIfMissing, findNode } from '../utils/Utils'; import Analytics from '../parser/youtube/Analytics'; import TimeWatched from '../parser/youtube/TimeWatched'; +import AccountInfo from '../parser/youtube/AccountInfo'; class AccountManager { #actions; @@ -113,18 +114,8 @@ class AccountManager { * Retrieves channel info. */ async getInfo() { - const response = await this.#actions.account('account/accounts_list', { client: 'ANDROID' }); - - const account_item_section_renderer = findNode(response.data, 'contents', 'accountItem', 8, false); - const profile = account_item_section_renderer.accountItem.serviceEndpoint.signInEndpoint.directSigninUserProfile; - - const name = profile.accountName; - const email = profile.email; - const photo = profile.accountPhoto.thumbnails; - const subscriber_count = account_item_section_renderer.accountItem.accountByline.runs.map((run: any) => run.text).join(''); - const channel_id = response.data.contents[0].accountSectionListRenderer.footers[0].accountChannelRenderer.navigationEndpoint.browseEndpoint.browseId; - - return { name, email, channel_id, subscriber_count, photo }; + const response = await this.#actions.execute('/account/accounts_list', { client: 'ANDROID' }); + return new AccountInfo(response); } /** @@ -145,7 +136,7 @@ class AccountManager { async getAnalytics() { const info = await this.getInfo(); - const params = Proto.encodeChannelAnalyticsParams(info.channel_id); + const params = Proto.encodeChannelAnalyticsParams(info.footers?.endpoint.payload.browseId); const response = await this.#actions.browse('FEanalytics_screen', { params, client: 'ANDROID' }); return new Analytics(response); diff --git a/src/parser/classes/AccountChannel.ts b/src/parser/classes/AccountChannel.ts new file mode 100644 index 00000000..2a667c67 --- /dev/null +++ b/src/parser/classes/AccountChannel.ts @@ -0,0 +1,18 @@ +import Text from './misc/Text'; +import NavigationEndpoint from './NavigationEndpoint'; +import { YTNode } from '../helpers'; + +class AccountChannel extends YTNode { + static type = 'AccountChannel'; + + title: Text; + endpoint: NavigationEndpoint; + + constructor(data: any) { + super(); + this.title = new Text(data.title); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + } +} + +export default AccountChannel; \ No newline at end of file diff --git a/src/parser/classes/AccountItemSection.ts b/src/parser/classes/AccountItemSection.ts new file mode 100644 index 00000000..a00addf4 --- /dev/null +++ b/src/parser/classes/AccountItemSection.ts @@ -0,0 +1,45 @@ +import Parser from '..'; + +import Text from './misc/Text'; +import Thumbnail from './misc/Thumbnail'; +import NavigationEndpoint from './NavigationEndpoint'; +import AccountItemSectionHeader from './AccountItemSectionHeader'; + +import { YTNode } from '../helpers'; + +class AccountItem { + static type = 'AccountItem'; + + account_name: Text; + account_photo: Thumbnail[]; + is_selected: boolean; + is_disabled: boolean; + has_channel: boolean; + endpoint: NavigationEndpoint; + account_byline: Text; + + constructor(data: any) { + 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.endpoint = new NavigationEndpoint(data.serviceEndpoint); + this.account_byline = new Text(data.accountByline); + } +} + +class AccountItemSection extends YTNode { + static type = 'AccountItemSection'; + + contents; + header; + + constructor(data: any) { + super(); + this.contents = data.contents.map((ac: any) => new AccountItem(ac.accountItem)); + this.header = Parser.parseItem(data.header, AccountItemSectionHeader); + } +} + +export default AccountItemSection; \ No newline at end of file diff --git a/src/parser/classes/AccountItemSectionHeader.ts b/src/parser/classes/AccountItemSectionHeader.ts new file mode 100644 index 00000000..631378f1 --- /dev/null +++ b/src/parser/classes/AccountItemSectionHeader.ts @@ -0,0 +1,15 @@ +import Text from './misc/Text'; +import { YTNode } from '../helpers'; + +class AccountItemSectionHeader extends YTNode { + static type = 'AccountItemSectionHeader'; + + title: Text; + + constructor(data: any) { + super(); + this.title = new Text(data.title); + } +} + +export default AccountItemSectionHeader; \ No newline at end of file diff --git a/src/parser/classes/AccountSectionList.ts b/src/parser/classes/AccountSectionList.ts new file mode 100644 index 00000000..8d38cd3c --- /dev/null +++ b/src/parser/classes/AccountSectionList.ts @@ -0,0 +1,20 @@ +import Parser from '..'; +import AccountChannel from './AccountChannel'; +import AccountItemSection from './AccountItemSection'; + +import { YTNode } from '../helpers'; + +class AccountSectionList extends YTNode { + static type = 'AccountSectionList'; + + contents; + footers; + + constructor(data: any) { + super(); + 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 diff --git a/src/parser/map.ts b/src/parser/map.ts index d86ec297..8dcd5aa7 100644 --- a/src/parser/map.ts +++ b/src/parser/map.ts @@ -2,6 +2,10 @@ // See ./scripts/build-parser-json.js import { YTNodeConstructor } from './helpers'; +import { default as AccountChannel } from './classes/AccountChannel'; +import { default as AccountItemSection } from './classes/AccountItemSection'; +import { default as AccountItemSectionHeader } from './classes/AccountItemSectionHeader'; +import { default as AccountSectionList } from './classes/AccountSectionList'; import { default as AppendContinuationItemsAction } from './classes/actions/AppendContinuationItemsAction'; import { default as OpenPopupAction } from './classes/actions/OpenPopupAction'; import { default as AnalyticsMainAppKeyMetrics } from './classes/analytics/AnalyticsMainAppKeyMetrics'; @@ -246,6 +250,10 @@ import { default as WatchNextEndScreen } from './classes/WatchNextEndScreen'; import { default as WatchNextTabbedResults } from './classes/WatchNextTabbedResults'; const map: Record = { + AccountChannel, + AccountItemSection, + AccountItemSectionHeader, + AccountSectionList, AppendContinuationItemsAction, OpenPopupAction, AnalyticsMainAppKeyMetrics, diff --git a/src/parser/youtube/AccountInfo.ts b/src/parser/youtube/AccountInfo.ts new file mode 100644 index 00000000..d4d63ab4 --- /dev/null +++ b/src/parser/youtube/AccountInfo.ts @@ -0,0 +1,28 @@ +import Parser, { ParsedResponse } from '..'; +import { AxioslikeResponse } from '../../core/Actions'; + +import AccountSectionList from '../classes/AccountSectionList'; +import AccountItemSection from '../classes/AccountItemSection'; +import AccountChannel from '../classes/AccountChannel'; + +class AccountInfo { + #page; + + contents: AccountItemSection | null; + footers: AccountChannel | null; + + constructor(response: AxioslikeResponse) { + this.#page = Parser.parseResponse(response.data); + + const account_section_list = this.#page.contents.array().as(AccountSectionList)[0]; + + this.contents = account_section_list.contents; + this.footers = account_section_list.footers; + } + + get page(): ParsedResponse { + return this.#page; + } +} + +export default AccountInfo; \ No newline at end of file