Skip to content

Commit

Permalink
feat(yt): add getGuide() (#335)
Browse files Browse the repository at this point in the history
* feat(yt): add `getGuide()`

* chore: lint

* fix(Guide): wrong prop

* fix(Guide): include subscription section

* fix(Guide): wrong import

* feat(Guide): add `page`
  • Loading branch information
patrickkfkan authored Mar 4, 2023
1 parent 2d774e2 commit 2cc7b8b
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 1 deletion.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ const yt = await Innertube.create({
* [.getSearchSuggestions(query)](#getsearchsuggestions)
* [.getComments(video_id, sort_by?)](#getcomments)
* [.getHomeFeed()](#gethomefeed)
* [.getGuide()](#getguide)
* [.getLibrary()](#getlibrary)
* [.getHistory()](#gethistory)
* [.getTrending()](#gettrending)
Expand Down Expand Up @@ -426,6 +427,12 @@ Retrieves YouTube's home feed.
</p>
</details>

<a name="getguide"></a>
### getGuide()
Retrieves YouTube's content guide.

**Returns**: `Promise<Guide>`

<a name="getlibrary"></a>
### getLibrary()
Retrieves the account's library.
Expand Down
9 changes: 9 additions & 0 deletions src/Innertube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import PlaylistManager from './core/PlaylistManager.js';
import YTStudio from './core/Studio.js';
import TabbedFeed from './core/TabbedFeed.js';
import HomeFeed from './parser/youtube/HomeFeed.js';
import Guide from './parser/youtube/Guide.js';
import Proto from './proto/index.js';
import Constants from './utils/Constants.js';

Expand Down Expand Up @@ -170,6 +171,14 @@ class Innertube {
return new HomeFeed(this.actions, response);
}

/**
* Retrieves YouTube's content guide.
*/
async getGuide(): Promise<Guide> {
const response = await this.actions.execute('/guide');
return new Guide(response.data);
}

/**
* Returns the account's library.
*/
Expand Down
35 changes: 35 additions & 0 deletions src/parser/classes/GuideCollapsibleEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Text from './misc/Text.js';
import { YTNode } from '../helpers.js';
import Parser from '../parser.js';

class GuideCollapsibleEntry extends YTNode {
static type = 'GuideCollapsibleEntry';

expander_item: {
title: string,
icon_type: string
};
collapser_item: {
title: string,
icon_type: string
};
expandable_items;

constructor(data: any) {
super();

this.expander_item = {
title: new Text(data.expanderItem.guideEntryRenderer.formattedTitle).toString(),
icon_type: data.expanderItem.guideEntryRenderer.icon.iconType
};

this.collapser_item = {
title: new Text(data.collapserItem.guideEntryRenderer.formattedTitle).toString(),
icon_type: data.collapserItem.guideEntryRenderer.icon.iconType
};

this.expandable_items = Parser.parseArray(data.expandableItems);
}
}

export default GuideCollapsibleEntry;
23 changes: 23 additions & 0 deletions src/parser/classes/GuideCollapsibleSectionEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { YTNode } from '../helpers.js';
import Parser from '../parser.js';

class GuideCollapsibleSectionEntry extends YTNode {
static type = 'GuideCollapsibleSectionEntry';

header_entry;
expander_icon: string;
collapser_icon: string;
section_items;

constructor(data: any) {
super();

this.header_entry = Parser.parseItem(data.headerEntry);
this.expander_icon = data.expanderIcon.iconType;
this.collapser_icon = data.collapserIcon.iconType;
this.section_items = Parser.parseArray(data.sectionItems);

}
}

export default GuideCollapsibleSectionEntry;
14 changes: 14 additions & 0 deletions src/parser/classes/GuideDownloadsEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import GuideEntry from './GuideEntry.js';

class GuideDownloadsEntry extends GuideEntry {
static type = 'GuideDownloadsEntry';

always_show: boolean;

constructor(data: any) {
super(data.entryRenderer.guideEntryRenderer);
this.always_show = !!data.alwaysShow;
}
}

export default GuideDownloadsEntry;
33 changes: 33 additions & 0 deletions src/parser/classes/GuideEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Text from './misc/Text.js';
import NavigationEndpoint from './NavigationEndpoint.js';
import { YTNode } from '../helpers.js';
import Thumbnail from './misc/Thumbnail.js';

class GuideEntry extends YTNode {
static type = 'GuideEntry';

title: Text;
endpoint: NavigationEndpoint;
icon_type?: string;
thumbnails?: Thumbnail[];
badges?: any;
is_primary: boolean;

constructor(data: any) {
super();
this.title = new Text(data.formattedTitle);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint || data.serviceEndpoint);
if (data.icon?.iconType) {
this.icon_type = data.icon.iconType;
}
if (data.thumbnail) {
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
}
if (data.badges) {
this.badges = data.badges;
}
this.is_primary = !!data.isPrimary;
}
}

export default GuideEntry;
20 changes: 20 additions & 0 deletions src/parser/classes/GuideSection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Text from './misc/Text.js';
import { YTNode } from '../helpers.js';
import Parser from '../parser.js';

class GuideSection extends YTNode {
static type = 'GuideSection';

title?: Text;
items;

constructor(data: any) {
super();
if (data.formattedTitle) {
this.title = new Text(data.formattedTitle);
}
this.items = Parser.parseArray(data.items);
}
}

export default GuideSection;
7 changes: 7 additions & 0 deletions src/parser/classes/GuideSubscriptionsSection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import GuideSection from './GuideSection.js';

class GuideSubscriptionsSection extends GuideSection {
static type = 'GuideSubscriptionsSection';
}

export default GuideSubscriptionsSection;
18 changes: 18 additions & 0 deletions src/parser/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,18 @@ import { default as GridPlaylist } from './classes/GridPlaylist.js';
export { GridPlaylist };
import { default as GridVideo } from './classes/GridVideo.js';
export { GridVideo };
import { default as GuideCollapsibleEntry } from './classes/GuideCollapsibleEntry.js';
export { GuideCollapsibleEntry };
import { default as GuideCollapsibleSectionEntry } from './classes/GuideCollapsibleSectionEntry.js';
export { GuideCollapsibleSectionEntry };
import { default as GuideDownloadsEntry } from './classes/GuideDownloadsEntry.js';
export { GuideDownloadsEntry };
import { default as GuideEntry } from './classes/GuideEntry.js';
export { GuideEntry };
import { default as GuideSection } from './classes/GuideSection.js';
export { GuideSection };
import { default as GuideSubscriptionsSection } from './classes/GuideSubscriptionsSection.js';
export { GuideSubscriptionsSection };
import { default as HashtagHeader } from './classes/HashtagHeader.js';
export { HashtagHeader };
import { default as Heatmap } from './classes/Heatmap.js';
Expand Down Expand Up @@ -757,6 +769,12 @@ const map: Record<string, YTNodeConstructor> = {
GridHeader,
GridPlaylist,
GridVideo,
GuideCollapsibleEntry,
GuideCollapsibleSectionEntry,
GuideDownloadsEntry,
GuideEntry,
GuideSection,
GuideSubscriptionsSection,
HashtagHeader,
Heatmap,
HeatMarker,
Expand Down
11 changes: 10 additions & 1 deletion src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,14 @@ export default class Parser {
parsed_data.cards = cards;
}

this.#createMemo();
const items = this.parse(data.items);
if (items) {
parsed_data.items = items;
parsed_data.items_memo = this.#getMemo();
}
this.#clearMemo();

return parsed_data;
}

Expand Down Expand Up @@ -481,7 +489,8 @@ export default class Parser {
'RunAttestationCommand',
'CompactPromotedVideo',
'StatementBanner',
'SearchSubMenu'
'SearchSubMenu',
'GuideSigninPromo'
]);

static shouldIgnore(classname: string) {
Expand Down
7 changes: 7 additions & 0 deletions src/parser/types/ParsedResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface IParsedResponse {
sidebar_memo?: Memo;
live_chat_item_context_menu_supported_renderers?: YTNode;
live_chat_item_context_menu_supported_renderers_memo?: Memo;
items_memo?: Memo;
on_response_received_actions?: ObservedArray<ReloadContinuationItemsCommand | AppendContinuationItemsAction>;
on_response_received_actions_memo?: Memo;
on_response_received_endpoints?: ObservedArray<ReloadContinuationItemsCommand | AppendContinuationItemsAction>;
Expand Down Expand Up @@ -72,6 +73,7 @@ export interface IParsedResponse {
storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec;
endscreen?: Endscreen;
cards?: CardCollection;
items?: SuperParsedResult<YTNode>;
}

export interface IPlayerResponse {
Expand Down Expand Up @@ -156,4 +158,9 @@ export interface IUpdatedMetadataResponse {
actions: SuperParsedResult<YTNode>;
actions_memo: Memo;
continuation?: Continuation;
}

export interface IGuideResponse {
items: SuperParsedResult<YTNode>;
items_memo: Memo;
}
1 change: 1 addition & 0 deletions src/parser/types/RawResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ export interface IRawResponse {
storyboards?: RawNode;
endscreen?: RawNode;
cards?: RawNode;
items?: RawNode[];
frameworkUpdates?: any;
}
20 changes: 20 additions & 0 deletions src/parser/youtube/Guide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { IGuideResponse } from '../types/ParsedResponse.js';
import { IRawResponse, Parser } from '../index.js';
import { ObservedArray } from '../helpers.js';
import GuideSection from '../classes/GuideSection.js';
import GuideSubscriptionsSection from '../classes/GuideSubscriptionsSection.js';

export default class Guide {

#page: IGuideResponse;
contents: ObservedArray<GuideSection | GuideSubscriptionsSection>;

constructor(data: IRawResponse) {
this.#page = Parser.parseResponse<IGuideResponse>(data);
this.contents = this.#page.items.array().as(GuideSection, GuideSubscriptionsSection);
}

get page(): IGuideResponse {
return this.#page;
}
}

0 comments on commit 2cc7b8b

Please sign in to comment.