Skip to content

Commit

Permalink
feat(ytkids): add getChannel() (#292)
Browse files Browse the repository at this point in the history
  • Loading branch information
LuanRT authored Jan 23, 2023
1 parent 2bbefef commit 0fc29f0
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 2 deletions.
28 changes: 28 additions & 0 deletions docs/API/kids.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ YouTube Kids is a modified version of the YouTube app, with a simplified interfa
* Kids
* [.search(query)](#search)
* [.getInfo(video_id)](#getinfo)
* [.getChannel(channel_id)](#getchannel)
* [.getHomeFeed()](#gethomefeed)

<a name="search"></a>
Expand Down Expand Up @@ -64,6 +65,33 @@ Retrieves video info.
</p>
</details>

<a name="getchannel"></a>
### getChannel(channel_id)

Retrieves channel info.

**Returns:** `Promise.<Channel>`

| Param | Type | Description |
| --- | --- | --- |
| channel_id | `string` | The channel id |

<details>
<summary>Methods & Getters</summary>
<p>

- `<channel>#getContinuation()`
- Retrieves next batch of videos.

- `<channel>#has_continuation`
- Returns whether there are more videos to retrieve.

- `<channel>#page`
- Returns the original InnerTube response(s), parsed and sanitized.

</p>
</details>

<a name="gethomefeed"></a>
### getHomeFeed()

Expand Down
1 change: 1 addition & 0 deletions src/core/Feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Feed {

const memo = concatMemos(
this.#page.contents_memo,
this.#page.continuation_contents_memo,
this.#page.on_response_received_commands_memo,
this.#page.on_response_received_endpoints_memo,
this.#page.on_response_received_actions_memo,
Expand Down
11 changes: 11 additions & 0 deletions src/core/Kids.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Search from '../parser/ytkids/Search';
import HomeFeed from '../parser/ytkids/HomeFeed';
import VideoInfo from '../parser/ytkids/VideoInfo';
import Channel from '../parser/ytkids/Channel';
import type Session from './Session';

import { generateRandomString } from '../utils/Utils';

class Kids {
Expand Down Expand Up @@ -45,6 +47,15 @@ class Kids {
return new VideoInfo(response, this.#session.actions, cpn);
}

/**
* Retrieves the contents of the given channel.
* @param channel_id - The channel id.
*/
async getChannel(channel_id: string): Promise<Channel> {
const response = await this.#session.actions.execute('/browse', { browseId: channel_id, client: 'YTKIDS' });
return new Channel(this.#session.actions, response.data);
}

/**
* Retrieves the home feed.
*/
Expand Down
7 changes: 6 additions & 1 deletion src/parser/classes/ItemSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class ItemSection extends YTNode {

header: CommentsHeader | ItemSectionHeader | ItemSectionTabbedHeader | null;
contents;
target_id;
target_id?: string;
continuation?: string;

constructor(data: any) {
super();
Expand All @@ -20,6 +21,10 @@ class ItemSection extends YTNode {
if (data.targetId || data.sectionIdentifier) {
this.target_id = data?.target_id || data?.sectionIdentifier;
}

if (data.continuations) {
this.continuation = data.continuations?.at(0)?.nextContinuationData?.continuation;
}
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ export default class Parser {
}

static parseLC(data: any) {
if (data.itemSectionContinuation)
return new ItemSectionContinuation(data.itemSectionContinuation);
if (data.sectionListContinuation)
return new SectionListContinuation(data.sectionListContinuation);
if (data.liveChatContinuation)
Expand Down Expand Up @@ -387,7 +389,22 @@ export default class Parser {

export type ParsedResponse = ReturnType<typeof Parser.parseResponse>;

// Continuation nodes
// Continuation

export class ItemSectionContinuation extends YTNode {
static readonly type = 'itemSectionContinuation';

contents: ObservedArray<YTNode> | null;
continuation?: string;

constructor(data: any) {
super();
this.contents = Parser.parseArray(data.contents);
if (data.continuations) {
this.continuation = data.continuations?.at(0)?.nextContinuationData?.continuation;
}
}
}

export class AppendContinuationItemsAction extends YTNode {
static readonly type = 'appendContinuationItemsAction';
Expand Down
34 changes: 34 additions & 0 deletions src/parser/ytkids/Channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Feed from '../../core/Feed';
import Actions from '../../core/Actions';
import C4TabbedHeader from '../classes/C4TabbedHeader';
import ItemSection from '../classes/ItemSection';
import { ItemSectionContinuation } from '..';

class Channel extends Feed {
header?: C4TabbedHeader;
contents?: ItemSection | ItemSectionContinuation;

constructor(actions: Actions, data: any, already_parsed = false) {
super(actions, data, already_parsed);
this.header = this.page.header?.item().as(C4TabbedHeader);
this.contents = this.memo.getType(ItemSection).first() || this.page.continuation_contents?.as(ItemSectionContinuation);
}

/**
* Retrieves next batch of videos.
*/
async getContinuation(): Promise<Channel> {
const response = await this.actions.execute('/browse', {
continuation: this.contents?.continuation,
client: 'YTKIDS'
});

return new Channel(this.actions, response.data);
}

get has_continuation(): boolean {
return !!this.contents?.continuation;
}
}

export default Channel;
4 changes: 4 additions & 0 deletions test/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@ export const CHANNELS = [
{
ID: 'UCXuqSBlHAE6Xw-yeJA0Tunw',
NAME: 'Linus Tech Tips'
},
{
ID: 'UCpbpfcZfo-hoDAx2m1blFhg',
NAME: 'Learning Blocks'
}
];
5 changes: 5 additions & 0 deletions test/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ describe('YouTube.js Tests', () => {
const info = await yt.kids.getInfo(VIDEOS[6].ID);
expect(info.basic_info?.id).toBe(VIDEOS[6].ID);
});

it('should retrieve a channel', async () => {
const channel = await yt.kids.getChannel(CHANNELS[1].ID);
expect(channel.videos.length).toBeGreaterThan(0);
});
});
});

Expand Down

0 comments on commit 0fc29f0

Please sign in to comment.