From d6398296c3a45e2fe6d42c3d31e2a4ce57901246 Mon Sep 17 00:00:00 2001 From: LuanRT Date: Wed, 3 Aug 2022 17:06:00 -0300 Subject: [PATCH] docs: update examples --- examples/channel/basic-info.js | 39 ------------------ examples/channel/basic-info.ts | 42 ++++++++++++++++++++ examples/comments/README.md | 2 +- examples/comments/index.js | 33 ---------------- examples/comments/index.ts | 39 ++++++++++++++++++ examples/livechat/README.md | 2 +- src/parser/classes/NavigationEndpoint.ts | 16 +++----- src/parser/youtube/Comments.ts | 50 ++++++++++++++---------- 8 files changed, 118 insertions(+), 105 deletions(-) delete mode 100644 examples/channel/basic-info.js create mode 100644 examples/channel/basic-info.ts delete mode 100644 examples/comments/index.js create mode 100644 examples/comments/index.ts diff --git a/examples/channel/basic-info.js b/examples/channel/basic-info.js deleted file mode 100644 index b8453b64..00000000 --- a/examples/channel/basic-info.js +++ /dev/null @@ -1,39 +0,0 @@ -const { Innertube } = require('../../dist/index'); - -(async () => { - -const session = await Innertube.create(); - -const channel = await session.getChannel('UCX6OQ3DkcsbYNE6H8uQQuVA'); - -console.log('Viewing channel:', channel.header.author.name); -console.log('Family Safe:', channel.metadata.is_family_safe); -const about = await channel.getAbout(); -console.log('Country:', about.country.toString()); - - -console.log('\nLists the following videos:'); -const videos = await channel.getVideos(); -for (const video of videos.videos) { - console.log('Video:', video.title.toString()); -} - -console.log('\nLists the following playlists:'); -const playlists = await channel.getPlaylists(); -for (const playlist of playlists.playlists) { - console.log('Playlist:', playlist.title.toString()); -} - -console.log('\nLists the following channels:'); -const channels = await channel.getChannels(); -for (const channel of channels.channels) { - console.log('Channel:', channel.author.name); -} - -console.log('\nLists the following community posts:'); -const posts = await channel.getCommunity(); -for (const post of posts.posts) { - console.log('Post:', post.content.toString().substring(0, 20) + '...'); -} - -})(); \ No newline at end of file diff --git a/examples/channel/basic-info.ts b/examples/channel/basic-info.ts new file mode 100644 index 00000000..06bfa18e --- /dev/null +++ b/examples/channel/basic-info.ts @@ -0,0 +1,42 @@ +import { Innertube, UniversalCache } from 'youtubei.js'; + +(async () => { + const yt = await Innertube.create({ cache: new UniversalCache() }); + + const channel = await yt.getChannel('UCX6OQ3DkcsbYNE6H8uQQuVA'); + + console.info('Viewing channel:', channel.header.author.name); + console.info('Family Safe:', channel.metadata.is_family_safe); + + const about = await channel.getAbout(); + + console.info('Country:', about.country.toString()); + + console.info('\nLists the following videos:'); + const videos = await channel.getVideos(); + + for (const video of videos.videos) { + console.info('Video:', video.title.toString()); + } + + console.info('\nLists the following playlists:'); + const playlists = await channel.getPlaylists(); + + for (const playlist of playlists.playlists) { + console.info('Playlist:', playlist.title.toString()); + } + + console.info('\nLists the following channels:'); + const channels = await channel.getChannels(); + + for (const channel of channels.channels) { + console.info('Channel:', channel.author.name); + } + + console.info('\nLists the following community posts:'); + const posts = await channel.getCommunity(); + + for (const post of posts.posts) { + console.info('Post:', post.content.toString().substring(0, 20) + '...'); + } +})(); \ No newline at end of file diff --git a/examples/comments/README.md b/examples/comments/README.md index c8517249..fd4e786d 100644 --- a/examples/comments/README.md +++ b/examples/comments/README.md @@ -44,4 +44,4 @@ Returns original InnerTube response (sanitized). **Returns:** `Promise.` ## Example -See [`index.js`]('./index.js'). \ No newline at end of file +See [`index.ts`]('./index.ts'). \ No newline at end of file diff --git a/examples/comments/index.js b/examples/comments/index.js deleted file mode 100644 index f90433f7..00000000 --- a/examples/comments/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import Innertube from 'youtubei.js'; - -const session = await new Innertube(); - -const comments = await session.getComments('a-rqu-hjobc'); - -console.info(`This video has ${comments.header.comments_count.toString()} comments.`); - -for (const thread of comments.contents) { - const comment = thread.comment; - - console.info( - `${comment.author.name} • ${comment.published}\n`, - `${comment.content.toString()}`, '\n', - `Likes: ${comment.vote_count.short_text}`, '\n' - ); - - if (comment.reply_count > 0) { - console.info('Replies:', '\n'); - - const comment_thread = await thread.getReplies(); - - for (const reply of comment_thread.replies) { - console.info( - `> ${reply.author.name} • ${reply.published}\n`, - `${reply.content.toString()}`, '\n', - `Likes: ${reply.vote_count.short_text}`, '\n' - ); - } - } - - console.log('\n'); -} \ No newline at end of file diff --git a/examples/comments/index.ts b/examples/comments/index.ts new file mode 100644 index 00000000..11a9208d --- /dev/null +++ b/examples/comments/index.ts @@ -0,0 +1,39 @@ +import { Innertube, UniversalCache } from 'youtubei.js'; + +(async () => { + const yt = await Innertube.create({ cache: new UniversalCache() }); + + const comments = await yt.getComments('a-rqu-hjobc'); + + console.info(`This video has ${comments.header?.comments_count.toString() || 'N/A'} comments.\n`); + + for (const thread of comments.contents) { + const comment = thread.comment; + + if (comment) { + console.info( + `${comment.author.name} • ${comment.published}\n`, + `${comment.content.toString()}`, '\n', + `Likes: ${comment.vote_count.short_text}`, '\n' + ); + + if (comment.reply_count > 0) { + console.info('Replies:', '\n'); + + const comment_thread = await thread.getReplies(); + + if (comment_thread.replies) { + for (const reply of comment_thread.replies) { + console.info( + `> ${reply.author.name} • ${reply.published}\n`, + `${reply.content.toString()}`, '\n', + `Likes: ${reply.vote_count.short_text}`, '\n' + ); + } + } + } + } + + console.log('\n'); + } +})(); \ No newline at end of file diff --git a/examples/livechat/README.md b/examples/livechat/README.md index ef5e30a9..3288ba32 100644 --- a/examples/livechat/README.md +++ b/examples/livechat/README.md @@ -69,4 +69,4 @@ Sends a message. **Returns:** `Promise>` ## Example -See [`index.js`]('./index.js'). +See [`index.ts`]('./index.ts'). diff --git a/src/parser/classes/NavigationEndpoint.ts b/src/parser/classes/NavigationEndpoint.ts index 3e11a9f9..0e9451b1 100644 --- a/src/parser/classes/NavigationEndpoint.ts +++ b/src/parser/classes/NavigationEndpoint.ts @@ -221,26 +221,22 @@ class NavigationEndpoint extends YTNode { */ async callTest(actions: Actions, args: { parse: false; - params?: { [key: string]: any; } + params?: object }): Promise; async callTest(actions: Actions, args?: { - parse: true; - params?: { [key: string]: any; } + parse?: true; + params?: object }): Promise; async callTest(actions: Actions, args: { - parse: boolean; - params: { [key: string]: any; } - }): Promise; - async callTest(actions: Actions, args?: { parse?: boolean; - params?: { [key: string]: any; } - }): Promise { + params?: object + } = { parse: true, params: {} }): Promise { if (!actions) throw new Error('An active caller must be provided'); if (!this.metadata.api_url) throw new Error('Expected an api_url, but none was found, this is a bug.'); - const response = await actions.execute(this.metadata.api_url, { ...this.payload, ...(args?.params || {}), parse: args ? args.parse : true }); + const response = await actions.execute(this.metadata.api_url, { ...this.payload, ...args.params, parse: args.parse }); return response; } diff --git a/src/parser/youtube/Comments.ts b/src/parser/youtube/Comments.ts index 9a46d784..9ea8e99a 100644 --- a/src/parser/youtube/Comments.ts +++ b/src/parser/youtube/Comments.ts @@ -1,18 +1,19 @@ +import Parser, { ParsedResponse } from '..'; +import Actions, { ActionsResponse } from '../../core/Actions'; +import { InnertubeError } from '../../utils/Utils'; + +import Button from '../classes/Button'; import CommentsHeader from '../classes/comments/CommentsHeader'; import CommentSimplebox from '../classes/comments/CommentSimplebox'; import CommentThread from '../classes/comments/CommentThread'; import ContinuationItem from '../classes/ContinuationItem'; -import NavigationEndpoint from '../classes/NavigationEndpoint'; - -import Actions from '../../core/Actions'; -import { InnertubeError } from '../../utils/Utils'; -import Parser, { ParsedResponse } from '../index'; class Comments { #page: ParsedResponse; - #actions; - #continuation; - header; + #actions: Actions; + #continuation: ContinuationItem | undefined; + + header: CommentsHeader | undefined; contents; constructor(actions: Actions, data: any, already_parsed = false) { @@ -20,34 +21,41 @@ class Comments { this.#actions = actions; const contents = this.#page.on_response_received_endpoints; - this.header = contents?.[0].contents?.get({ type: 'CommentsHeader' })?.as(CommentsHeader); - // TODO: validate this - const threads: CommentThread[] = contents?.[1].contents?.getAll({ type: 'CommentThread' }) as CommentThread[]; + if (!contents) + throw new InnertubeError('Comments page did not have any content.'); + + this.header = contents[0].contents?.get({ type: 'CommentsHeader' })?.as(CommentsHeader); + + const threads: CommentThread[] = contents[1].contents?.filterType(CommentThread) || []; this.contents = threads.map((thread) => { thread.comment?.setActions(this.#actions); thread.setActions(this.#actions); return thread; - }); + }) as CommentThread[]; - this.#continuation = contents?.[1].contents?.get({ type: 'ContinuationItem' })?.as(ContinuationItem); + this.#continuation = contents[1].contents?.get({ type: 'ContinuationItem' })?.as(ContinuationItem); } /** * Creates a top-level comment. */ - async createComment(text: string) { - const button = this.header?.create_renderer?.as(CommentSimplebox).submit_button.item(); + async createComment(text: string): Promise { + if (!this.header) + throw new InnertubeError('Page header is missing.'); - const payload = { + const button = this.header.create_renderer?.as(CommentSimplebox).submit_button.item().as(Button); + + if (!button) + throw new InnertubeError('Could not find target button.'); + + const response = await button.endpoint.callTest(this.#actions, { params: { commentText: text }, parse: false - }; - - const response = await button?.key('endpoint').nodeOfType(NavigationEndpoint).callTest(this.#actions, payload); + }); return response; } @@ -55,7 +63,7 @@ class Comments { /** * Retrieves next batch of comments. */ - async getContinuation() { + async getContinuation(): Promise { if (!this.#continuation) throw new InnertubeError('Continuation not found'); @@ -74,7 +82,7 @@ class Comments { return new Comments(this.#actions, page, true); } - get page() { + get page(): ParsedResponse { return this.#page; } }