diff --git a/README.md b/README.md
index d69a705b..79a24427 100644
--- a/README.md
+++ b/README.md
@@ -660,6 +660,16 @@ console.info('Playback url:', url);
| video_id | `string` | Video id |
| options | `FormatOptions` | Format options |
+
+### `getTranscript(video_id)`
+Retrieves a given video's transcript.
+
+**Returns**: `Promise`
+
+| Param | Type | Description |
+| --- | --- | --- |
+| video_id | `string` | Video id |
+
### `download(video_id, options?)`
Downloads a given video.
diff --git a/deno/package.json b/deno/package.json
index f07fa49c..2d830fae 100644
--- a/deno/package.json
+++ b/deno/package.json
@@ -1,6 +1,6 @@
{
"name": "youtubei.js",
- "version": "6.3.0",
+ "version": "6.4.0",
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).",
"type": "module",
"types": "./dist/src/platform/lib.d.ts",
diff --git a/deno/src/Innertube.ts b/deno/src/Innertube.ts
index 90829891..ebc9608b 100644
--- a/deno/src/Innertube.ts
+++ b/deno/src/Innertube.ts
@@ -14,6 +14,8 @@ import NotificationsMenu from './parser/youtube/NotificationsMenu.ts';
import Playlist from './parser/youtube/Playlist.ts';
import Search from './parser/youtube/Search.ts';
import VideoInfo from './parser/youtube/VideoInfo.ts';
+import ContinuationItem from './parser/classes/ContinuationItem.ts';
+import Transcript from './parser/classes/Transcript.ts';
import { Kids, Music, Studio } from './core/clients/index.ts';
import { AccountManager, InteractionManager, PlaylistManager } from './core/managers/index.ts';
@@ -36,7 +38,7 @@ import {
import { GetUnseenCountEndpoint } from './core/endpoints/notification/index.ts';
import type { ApiResponse } from './core/Actions.ts';
-import type { IBrowseResponse, IParsedResponse } from './parser/types/index.ts';
+import { type IGetTranscriptResponse, type IBrowseResponse, type IParsedResponse } from './parser/types/index.ts';
import type { INextRequest } from './types/index.ts';
import type { DownloadOptions, FormatOptions } from './types/FormatUtils.ts';
@@ -332,6 +334,35 @@ export default class Innertube {
return info.chooseFormat(options);
}
+ /**
+ * Retrieves a video's transcript.
+ * @param video_id - The video id.
+ */
+ async getTranscript(video_id: string): Promise {
+ throwIfMissing({ video_id });
+
+ const next_response = await this.actions.execute(NextEndpoint.PATH, { ...NextEndpoint.build({ video_id }), parse: true });
+
+ if (!next_response.engagement_panels)
+ throw new InnertubeError('Engagement panels not found. Video likely has no transcript.');
+
+ const transcript_panel = next_response.engagement_panels.get({
+ panel_identifier: 'engagement-panel-searchable-transcript'
+ });
+
+ if (!transcript_panel)
+ throw new InnertubeError('Transcript panel not found. Video likely has no transcript.');
+
+ const transcript_continuation = transcript_panel.content?.as(ContinuationItem);
+
+ if (!transcript_continuation)
+ throw new InnertubeError('Transcript continuation not found.');
+
+ const transcript_response = await transcript_continuation.endpoint.call(this.actions, { parse: true });
+
+ return transcript_response.actions_memo.getType(Transcript).first();
+ }
+
/**
* Downloads a given video. If you only need the direct download link see {@link getStreamingData}.
* If you wish to retrieve the video info too, have a look at {@link getBasicInfo} or {@link getInfo}.
diff --git a/deno/src/core/endpoints/browse/EditPlaylistEndpoint.ts b/deno/src/core/endpoints/browse/EditPlaylistEndpoint.ts
index c9d6d418..6407d805 100644
--- a/deno/src/core/endpoints/browse/EditPlaylistEndpoint.ts
+++ b/deno/src/core/endpoints/browse/EditPlaylistEndpoint.ts
@@ -15,7 +15,9 @@ export function build(opts: EditPlaylistEndpointOptions): IEditPlaylistRequest {
...{
addedVideoId: action.added_video_id,
setVideoId: action.set_video_id,
- movedSetVideoIdPredecessor: action.moved_set_video_id_predecessor
+ movedSetVideoIdPredecessor: action.moved_set_video_id_predecessor,
+ playlistDescription: action.playlist_description,
+ playlistName: action.playlist_name
}
}))
};
diff --git a/deno/src/core/managers/PlaylistManager.ts b/deno/src/core/managers/PlaylistManager.ts
index 131301af..df7f8b4c 100644
--- a/deno/src/core/managers/PlaylistManager.ts
+++ b/deno/src/core/managers/PlaylistManager.ts
@@ -200,4 +200,60 @@ export default class PlaylistManager {
action_result: response.data.actions // TODO: implement actions in the parser
};
}
-}
\ No newline at end of file
+
+ /**
+ * Sets the name (title) for the given playlist.
+ * @param playlist_id - The playlist ID.
+ * @param name - The name / title to use for the playlist.
+ */
+ async setName(playlist_id: string, name: string): Promise<{ playlist_id: string; action_result: any; }> {
+ throwIfMissing({ playlist_id, name });
+
+ if (!this.#actions.session.logged_in)
+ throw new InnertubeError('You must be signed in to perform this operation.');
+
+ const payload: EditPlaylistEndpointOptions = { playlist_id, actions: [] };
+
+ payload.actions.push({
+ action: 'ACTION_SET_PLAYLIST_NAME',
+ playlist_name: name
+ });
+
+ const response = await this.#actions.execute(
+ EditPlaylistEndpoint.PATH, EditPlaylistEndpoint.build(payload)
+ );
+
+ return {
+ playlist_id,
+ action_result: response.data.actions
+ };
+ }
+
+ /**
+ * Sets the description for the given playlist.
+ * @param playlist_id - The playlist ID.
+ * @param description - The description to use for the playlist.
+ */
+ async setDescription(playlist_id: string, description: string): Promise<{ playlist_id: string; action_result: any; }> {
+ throwIfMissing({ playlist_id, description });
+
+ if (!this.#actions.session.logged_in)
+ throw new InnertubeError('You must be signed in to perform this operation.');
+
+ const payload: EditPlaylistEndpointOptions = { playlist_id, actions: [] };
+
+ payload.actions.push({
+ action: 'ACTION_SET_PLAYLIST_DESCRIPTION',
+ playlist_description: description
+ });
+
+ const response = await this.#actions.execute(
+ EditPlaylistEndpoint.PATH, EditPlaylistEndpoint.build(payload)
+ );
+
+ return {
+ playlist_id,
+ action_result: response.data.actions
+ };
+ }
+}
diff --git a/deno/src/parser/classes/BackstagePost.ts b/deno/src/parser/classes/BackstagePost.ts
index e9449893..20bc1629 100644
--- a/deno/src/parser/classes/BackstagePost.ts
+++ b/deno/src/parser/classes/BackstagePost.ts
@@ -1,5 +1,6 @@
import { YTNode } from '../helpers.ts';
import Parser, { type RawNode } from '../index.ts';
+import Button from './Button.ts';
import NavigationEndpoint from './NavigationEndpoint.ts';
import CommentActionButtons from './comments/CommentActionButtons.ts';
import Menu from './menus/Menu.ts';
@@ -18,7 +19,7 @@ export default class BackstagePost extends YTNode {
vote_count?: Text;
menu?: Menu | null;
action_buttons?: CommentActionButtons | null;
- vote_button?: CommentActionButtons | null;
+ vote_button?: Button | null;
surface: string;
endpoint?: NavigationEndpoint;
attachment;
@@ -56,7 +57,7 @@ export default class BackstagePost extends YTNode {
}
if (Reflect.has(data, 'voteButton')) {
- this.vote_button = Parser.parseItem(data.voteButton, CommentActionButtons);
+ this.vote_button = Parser.parseItem(data.voteButton, Button);
}
if (Reflect.has(data, 'navigationEndpoint')) {
diff --git a/deno/src/parser/classes/EngagementPanelSectionList.ts b/deno/src/parser/classes/EngagementPanelSectionList.ts
index 3e08ea0f..83f24332 100644
--- a/deno/src/parser/classes/EngagementPanelSectionList.ts
+++ b/deno/src/parser/classes/EngagementPanelSectionList.ts
@@ -3,6 +3,7 @@ import Parser, { type RawNode } from '../index.ts';
import ContinuationItem from './ContinuationItem.ts';
import EngagementPanelTitleHeader from './EngagementPanelTitleHeader.ts';
import MacroMarkersList from './MacroMarkersList.ts';
+import ProductList from './ProductList.ts';
import SectionList from './SectionList.ts';
import StructuredDescriptionContent from './StructuredDescriptionContent.ts';
@@ -10,7 +11,7 @@ export default class EngagementPanelSectionList extends YTNode {
static type = 'EngagementPanelSectionList';
header: EngagementPanelTitleHeader | null;
- content: SectionList | ContinuationItem | StructuredDescriptionContent | MacroMarkersList | null;
+ content: SectionList | ContinuationItem | StructuredDescriptionContent | MacroMarkersList | ProductList | null;
target_id?: string;
panel_identifier?: string;
visibility?: string;
@@ -18,9 +19,9 @@ export default class EngagementPanelSectionList extends YTNode {
constructor(data: RawNode) {
super();
this.header = Parser.parseItem(data.header, EngagementPanelTitleHeader);
- this.content = Parser.parseItem(data.content, [ SectionList, ContinuationItem, StructuredDescriptionContent, MacroMarkersList ]);
+ this.content = Parser.parseItem(data.content, [ SectionList, ContinuationItem, StructuredDescriptionContent, MacroMarkersList, ProductList ]);
this.panel_identifier = data.panelIdentifier;
this.target_id = data.targetId;
this.visibility = data.visibility;
}
-}
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/ExpandableMetadata.ts b/deno/src/parser/classes/ExpandableMetadata.ts
index b49dd5ee..bd529e83 100644
--- a/deno/src/parser/classes/ExpandableMetadata.ts
+++ b/deno/src/parser/classes/ExpandableMetadata.ts
@@ -2,6 +2,7 @@ import { YTNode } from '../helpers.ts';
import Parser, { type RawNode } from '../index.ts';
import Button from './Button.ts';
import HorizontalCardList from './HorizontalCardList.ts';
+import HorizontalList from './HorizontalList.ts';
import Text from './misc/Text.ts';
import Thumbnail from './misc/Thumbnail.ts';
@@ -15,7 +16,7 @@ export default class ExpandableMetadata extends YTNode {
expanded_title: Text;
};
- expanded_content: HorizontalCardList | null;
+ expanded_content: HorizontalCardList | HorizontalList | null;
expand_button: Button | null;
collapse_button: Button | null;
@@ -31,7 +32,7 @@ export default class ExpandableMetadata extends YTNode {
};
}
- this.expanded_content = Parser.parseItem(data.expandedContent, HorizontalCardList);
+ this.expanded_content = Parser.parseItem(data.expandedContent, [ HorizontalCardList, HorizontalList ]);
this.expand_button = Parser.parseItem(data.expandButton, Button);
this.collapse_button = Parser.parseItem(data.collapseButton, Button);
}
diff --git a/deno/src/parser/classes/FancyDismissibleDialog.ts b/deno/src/parser/classes/FancyDismissibleDialog.ts
new file mode 100644
index 00000000..d27a3a2e
--- /dev/null
+++ b/deno/src/parser/classes/FancyDismissibleDialog.ts
@@ -0,0 +1,16 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import { Text } from '../misc.ts';
+
+export default class FancyDismissibleDialog extends YTNode {
+ static type = 'FancyDismissibleDialog';
+
+ dialog_message: Text;
+ confirm_label: Text;
+
+ constructor(data: RawNode) {
+ super();
+ this.dialog_message = new Text(data.dialogMessage);
+ this.confirm_label = new Text(data.confirmLabel);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/ProductList.ts b/deno/src/parser/classes/ProductList.ts
new file mode 100644
index 00000000..2c24c883
--- /dev/null
+++ b/deno/src/parser/classes/ProductList.ts
@@ -0,0 +1,15 @@
+import type { ObservedArray} from '../helpers.ts';
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+
+export default class ProductList extends YTNode {
+ static type = 'ProductList';
+
+ contents: ObservedArray;
+
+ constructor(data: RawNode) {
+ super();
+ this.contents = Parser.parseArray(data.contents);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/ProductListHeader.ts b/deno/src/parser/classes/ProductListHeader.ts
new file mode 100644
index 00000000..e87a96c8
--- /dev/null
+++ b/deno/src/parser/classes/ProductListHeader.ts
@@ -0,0 +1,16 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import { Text } from '../misc.ts';
+
+export default class ProductListHeader extends YTNode {
+ static type = 'ProductListHeader';
+
+ title: Text;
+ suppress_padding_disclaimer: boolean;
+
+ constructor(data: RawNode) {
+ super();
+ this.title = new Text(data.title);
+ this.suppress_padding_disclaimer = !!data.suppressPaddingDisclaimer;
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/ProductListItem.ts b/deno/src/parser/classes/ProductListItem.ts
new file mode 100644
index 00000000..98116b49
--- /dev/null
+++ b/deno/src/parser/classes/ProductListItem.ts
@@ -0,0 +1,31 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import { Text, Thumbnail } from '../misc.ts';
+import Button from './Button.ts';
+import NavigationEndpoint from './NavigationEndpoint.ts';
+
+export default class ProductListItem extends YTNode {
+ static type = 'ProductListItem';
+
+ title: Text;
+ accessibility_title: string;
+ thumbnail: Thumbnail[];
+ price: string;
+ endpoint: NavigationEndpoint;
+ merchant_name: string;
+ stay_in_app: boolean;
+ view_button: Button | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.title = new Text(data.title);
+ this.accessibility_title = data.accessibilityTitle;
+ this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
+ this.price = data.price;
+ this.endpoint = new NavigationEndpoint(data.onClickCommand);
+ this.merchant_name = data.merchantName;
+ this.stay_in_app = !!data.stayInApp;
+ this.view_button = Parser.parseItem(data.viewButton, Button);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/StructuredDescriptionContent.ts b/deno/src/parser/classes/StructuredDescriptionContent.ts
index 10264e3c..494dde02 100644
--- a/deno/src/parser/classes/StructuredDescriptionContent.ts
+++ b/deno/src/parser/classes/StructuredDescriptionContent.ts
@@ -5,11 +5,15 @@ import HorizontalCardList from './HorizontalCardList.ts';
import VideoDescriptionHeader from './VideoDescriptionHeader.ts';
import VideoDescriptionInfocardsSection from './VideoDescriptionInfocardsSection.ts';
import VideoDescriptionMusicSection from './VideoDescriptionMusicSection.ts';
+import type VideoDescriptionTranscriptSection from './VideoDescriptionTranscriptSection.ts';
export default class StructuredDescriptionContent extends YTNode {
static type = 'StructuredDescriptionContent';
- items: ObservedArray;
+ items: ObservedArray<
+ VideoDescriptionHeader | ExpandableVideoDescriptionBody | VideoDescriptionMusicSection |
+ VideoDescriptionInfocardsSection | VideoDescriptionTranscriptSection | HorizontalCardList
+ >;
constructor(data: RawNode) {
super();
diff --git a/deno/src/parser/classes/Transcript.ts b/deno/src/parser/classes/Transcript.ts
new file mode 100644
index 00000000..85ed5361
--- /dev/null
+++ b/deno/src/parser/classes/Transcript.ts
@@ -0,0 +1,15 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import TranscriptSearchPanel from './TranscriptSearchPanel.ts';
+
+export default class Transcript extends YTNode {
+ static type = 'Transcript';
+
+ content: TranscriptSearchPanel | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.content = Parser.parseItem(data.content, TranscriptSearchPanel);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/TranscriptFooter.ts b/deno/src/parser/classes/TranscriptFooter.ts
new file mode 100644
index 00000000..3dec3f91
--- /dev/null
+++ b/deno/src/parser/classes/TranscriptFooter.ts
@@ -0,0 +1,15 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import SortFilterSubMenu from './SortFilterSubMenu.ts';
+
+export default class TranscriptFooter extends YTNode {
+ static type = 'TranscriptFooter';
+
+ language_menu: SortFilterSubMenu | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.language_menu = Parser.parseItem(data.languageMenu, SortFilterSubMenu);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/TranscriptSearchBox.ts b/deno/src/parser/classes/TranscriptSearchBox.ts
new file mode 100644
index 00000000..3d892091
--- /dev/null
+++ b/deno/src/parser/classes/TranscriptSearchBox.ts
@@ -0,0 +1,23 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import Button from './Button.ts';
+import NavigationEndpoint from './NavigationEndpoint.ts';
+import { Text } from '../misc.ts';
+
+export default class TranscriptSearchBox extends YTNode {
+ static type = 'TranscriptSearchBox';
+
+ formatted_placeholder: Text;
+ clear_button: Button | null;
+ endpoint: NavigationEndpoint;
+ search_button: Button | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.formatted_placeholder = new Text(data.formattedPlaceholder);
+ this.clear_button = Parser.parseItem(data.clearButton, Button);
+ this.endpoint = new NavigationEndpoint(data.onTextChangeCommand);
+ this.search_button = Parser.parseItem(data.searchButton, Button);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/TranscriptSearchPanel.ts b/deno/src/parser/classes/TranscriptSearchPanel.ts
new file mode 100644
index 00000000..dd636613
--- /dev/null
+++ b/deno/src/parser/classes/TranscriptSearchPanel.ts
@@ -0,0 +1,23 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import TranscriptFooter from './TranscriptFooter.ts';
+import TranscriptSearchBox from './TranscriptSearchBox.ts';
+import TranscriptSegmentList from './TranscriptSegmentList.ts';
+
+export default class TranscriptSearchPanel extends YTNode {
+ static type = 'TranscriptSearchPanel';
+
+ header: TranscriptSearchBox | null;
+ body: TranscriptSegmentList | null;
+ footer: TranscriptFooter | null;
+ target_id: string;
+
+ constructor(data: RawNode) {
+ super();
+ this.header = Parser.parseItem(data.header, TranscriptSearchBox);
+ this.body = Parser.parseItem(data.body, TranscriptSegmentList);
+ this.footer = Parser.parseItem(data.footer, TranscriptFooter);
+ this.target_id = data.targetId;
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/TranscriptSegment.ts b/deno/src/parser/classes/TranscriptSegment.ts
new file mode 100644
index 00000000..5512c1cf
--- /dev/null
+++ b/deno/src/parser/classes/TranscriptSegment.ts
@@ -0,0 +1,22 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import { Text } from '../misc.ts';
+
+export default class TranscriptSegment extends YTNode {
+ static type = 'TranscriptSegment';
+
+ start_ms: string;
+ end_ms: string;
+ snippet: Text;
+ start_time_text: Text;
+ target_id: string;
+
+ constructor(data: RawNode) {
+ super();
+ this.start_ms = data.startMs;
+ this.end_ms = data.endMs;
+ this.snippet = new Text(data.snippet);
+ this.start_time_text = new Text(data.startTimeText);
+ this.target_id = data.targetId;
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/TranscriptSegmentList.ts b/deno/src/parser/classes/TranscriptSegmentList.ts
new file mode 100644
index 00000000..6f0c0fd2
--- /dev/null
+++ b/deno/src/parser/classes/TranscriptSegmentList.ts
@@ -0,0 +1,23 @@
+import type { ObservedArray} from '../helpers.ts';
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import { Text } from '../misc.ts';
+import TranscriptSegment from './TranscriptSegment.ts';
+
+export default class TranscriptSegmentList extends YTNode {
+ static type = 'TranscriptSegmentList';
+
+ initial_segments: ObservedArray;
+ no_result_label: Text;
+ retry_label: Text;
+ touch_captions_enabled: boolean;
+
+ constructor(data: RawNode) {
+ super();
+ this.initial_segments = Parser.parseArray(data.initialSegments, TranscriptSegment);
+ this.no_result_label = new Text(data.noResultLabel);
+ this.retry_label = new Text(data.retryLabel);
+ this.touch_captions_enabled = data.touchCaptionsEnabled;
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/UploadTimeFactoid.ts b/deno/src/parser/classes/UploadTimeFactoid.ts
new file mode 100644
index 00000000..93369916
--- /dev/null
+++ b/deno/src/parser/classes/UploadTimeFactoid.ts
@@ -0,0 +1,15 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import Factoid from './Factoid.ts';
+
+export default class UploadTimeFactoid extends YTNode {
+ static type = 'UploadTimeFactoid';
+
+ factoid: Factoid | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.factoid = Parser.parseItem(data.factoid, Factoid);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/VideoDescriptionHeader.ts b/deno/src/parser/classes/VideoDescriptionHeader.ts
index 2be7b72e..1ac2d41b 100644
--- a/deno/src/parser/classes/VideoDescriptionHeader.ts
+++ b/deno/src/parser/classes/VideoDescriptionHeader.ts
@@ -3,6 +3,8 @@ import Parser, { type RawNode } from '../index.ts';
import { Text, Thumbnail } from '../misc.ts';
import Factoid from './Factoid.ts';
import NavigationEndpoint from './NavigationEndpoint.ts';
+import UploadTimeFactoid from './UploadTimeFactoid.ts';
+import ViewCountFactoid from './ViewCountFactoid.ts';
export default class VideoDescriptionHeader extends YTNode {
static type = 'VideoDescriptionHeader';
@@ -10,7 +12,7 @@ export default class VideoDescriptionHeader extends YTNode {
channel: Text;
channel_navigation_endpoint?: NavigationEndpoint;
channel_thumbnail: Thumbnail[];
- factoids: ObservedArray;
+ factoids: ObservedArray;
publish_date: Text;
title: Text;
views: Text;
@@ -23,6 +25,6 @@ export default class VideoDescriptionHeader extends YTNode {
this.channel_thumbnail = Thumbnail.fromResponse(data.channelThumbnail);
this.publish_date = new Text(data.publishDate);
this.views = new Text(data.views);
- this.factoids = Parser.parseArray(data.factoid, Factoid);
+ this.factoids = Parser.parseArray(data.factoid, [ Factoid, ViewCountFactoid, UploadTimeFactoid ]);
}
}
diff --git a/deno/src/parser/classes/VideoDescriptionTranscriptSection.ts b/deno/src/parser/classes/VideoDescriptionTranscriptSection.ts
new file mode 100644
index 00000000..34254e7d
--- /dev/null
+++ b/deno/src/parser/classes/VideoDescriptionTranscriptSection.ts
@@ -0,0 +1,20 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import { Text } from '../misc.ts';
+import Button from './Button.ts';
+
+export default class VideoDescriptionTranscriptSection extends YTNode {
+ static type = 'VideoDescriptionTranscriptSection';
+
+ section_title: Text;
+ sub_header_text: Text;
+ primary_button: Button | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.section_title = new Text(data.sectionTitle);
+ this.sub_header_text = new Text(data.subHeaderText);
+ this.primary_button = Parser.parseItem(data.primaryButton, Button);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/ViewCountFactoid.ts b/deno/src/parser/classes/ViewCountFactoid.ts
new file mode 100644
index 00000000..8440a64f
--- /dev/null
+++ b/deno/src/parser/classes/ViewCountFactoid.ts
@@ -0,0 +1,19 @@
+import { YTNode } from '../helpers.ts';
+import type { RawNode } from '../index.ts';
+import Parser from '../index.ts';
+import Factoid from './Factoid.ts';
+
+export default class ViewCountFactoid extends YTNode {
+ static type = 'ViewCountFactoid';
+
+ view_count_entity_key: string;
+ factoid: Factoid | null;
+ view_count_type: string;
+
+ constructor(data: RawNode) {
+ super();
+ this.view_count_entity_key = data.viewCountEntityKey;
+ this.factoid = Parser.parseItem(data.factoid, [ Factoid ]);
+ this.view_count_type = data.viewCountType;
+ }
+}
diff --git a/deno/src/parser/classes/actions/UpdateEngagementPanelAction.ts b/deno/src/parser/classes/actions/UpdateEngagementPanelAction.ts
new file mode 100644
index 00000000..44848394
--- /dev/null
+++ b/deno/src/parser/classes/actions/UpdateEngagementPanelAction.ts
@@ -0,0 +1,17 @@
+import { YTNode } from '../../helpers.ts';
+import type { RawNode } from '../../index.ts';
+import Parser from '../../index.ts';
+import Transcript from '../Transcript.ts';
+
+export default class UpdateEngagementPanelAction extends YTNode {
+ static type = 'UpdateEngagementPanelAction';
+
+ target_id: string;
+ content: Transcript | null;
+
+ constructor(data: RawNode) {
+ super();
+ this.target_id = data.targetId;
+ this.content = Parser.parseItem(data.content, Transcript);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/classes/menus/MenuPopup.ts b/deno/src/parser/classes/menus/MenuPopup.ts
new file mode 100644
index 00000000..dceb8145
--- /dev/null
+++ b/deno/src/parser/classes/menus/MenuPopup.ts
@@ -0,0 +1,17 @@
+import type { ObservedArray} from '../../helpers.ts';
+import { YTNode } from '../../helpers.ts';
+import type { RawNode } from '../../index.ts';
+import Parser from '../../index.ts';
+import MenuNavigationItem from './MenuNavigationItem.ts';
+import MenuServiceItem from './MenuServiceItem.ts';
+
+export default class MenuPopup extends YTNode {
+ static type = 'MenuPopup';
+
+ items: ObservedArray;
+
+ constructor(data: RawNode) {
+ super();
+ this.items = Parser.parseArray(data.items, [ MenuNavigationItem, MenuServiceItem ]);
+ }
+}
\ No newline at end of file
diff --git a/deno/src/parser/nodes.ts b/deno/src/parser/nodes.ts
index db7c8e86..3d491634 100644
--- a/deno/src/parser/nodes.ts
+++ b/deno/src/parser/nodes.ts
@@ -7,6 +7,7 @@ export { default as AccountItemSectionHeader } from './classes/AccountItemSectio
export { default as AccountSectionList } from './classes/AccountSectionList.ts';
export { default as AppendContinuationItemsAction } from './classes/actions/AppendContinuationItemsAction.ts';
export { default as OpenPopupAction } from './classes/actions/OpenPopupAction.ts';
+export { default as UpdateEngagementPanelAction } from './classes/actions/UpdateEngagementPanelAction.ts';
export { default as Alert } from './classes/Alert.ts';
export { default as AlertWithButton } from './classes/AlertWithButton.ts';
export { default as AnalyticsMainAppKeyMetrics } from './classes/analytics/AnalyticsMainAppKeyMetrics.ts';
@@ -102,6 +103,7 @@ export { default as ExpandableTab } from './classes/ExpandableTab.ts';
export { default as ExpandableVideoDescriptionBody } from './classes/ExpandableVideoDescriptionBody.ts';
export { default as ExpandedShelfContents } from './classes/ExpandedShelfContents.ts';
export { default as Factoid } from './classes/Factoid.ts';
+export { default as FancyDismissibleDialog } from './classes/FancyDismissibleDialog.ts';
export { default as FeedFilterChipBar } from './classes/FeedFilterChipBar.ts';
export { default as FeedTabbedHeader } from './classes/FeedTabbedHeader.ts';
export { default as GameCard } from './classes/GameCard.ts';
@@ -191,6 +193,7 @@ export { default as MacroMarkersList } from './classes/MacroMarkersList.ts';
export { default as MacroMarkersListItem } from './classes/MacroMarkersListItem.ts';
export { default as Menu } from './classes/menus/Menu.ts';
export { default as MenuNavigationItem } from './classes/menus/MenuNavigationItem.ts';
+export { default as MenuPopup } from './classes/menus/MenuPopup.ts';
export { default as MenuServiceItem } from './classes/menus/MenuServiceItem.ts';
export { default as MenuServiceItemDownload } from './classes/menus/MenuServiceItemDownload.ts';
export { default as MultiPageMenu } from './classes/menus/MultiPageMenu.ts';
@@ -274,6 +277,9 @@ export { default as PlaylistVideoThumbnail } from './classes/PlaylistVideoThumbn
export { default as Poll } from './classes/Poll.ts';
export { default as Post } from './classes/Post.ts';
export { default as PostMultiImage } from './classes/PostMultiImage.ts';
+export { default as ProductList } from './classes/ProductList.ts';
+export { default as ProductListHeader } from './classes/ProductListHeader.ts';
+export { default as ProductListItem } from './classes/ProductListItem.ts';
export { default as ProfileColumn } from './classes/ProfileColumn.ts';
export { default as ProfileColumnStats } from './classes/ProfileColumnStats.ts';
export { default as ProfileColumnStatsEntry } from './classes/ProfileColumnStatsEntry.ts';
@@ -349,10 +355,17 @@ export { default as ToggleButton } from './classes/ToggleButton.ts';
export { default as ToggleMenuServiceItem } from './classes/ToggleMenuServiceItem.ts';
export { default as Tooltip } from './classes/Tooltip.ts';
export { default as TopicChannelDetails } from './classes/TopicChannelDetails.ts';
+export { default as Transcript } from './classes/Transcript.ts';
+export { default as TranscriptFooter } from './classes/TranscriptFooter.ts';
+export { default as TranscriptSearchBox } from './classes/TranscriptSearchBox.ts';
+export { default as TranscriptSearchPanel } from './classes/TranscriptSearchPanel.ts';
+export { default as TranscriptSegment } from './classes/TranscriptSegment.ts';
+export { default as TranscriptSegmentList } from './classes/TranscriptSegmentList.ts';
export { default as TwoColumnBrowseResults } from './classes/TwoColumnBrowseResults.ts';
export { default as TwoColumnSearchResults } from './classes/TwoColumnSearchResults.ts';
export { default as TwoColumnWatchNextResults } from './classes/TwoColumnWatchNextResults.ts';
export { default as UniversalWatchCard } from './classes/UniversalWatchCard.ts';
+export { default as UploadTimeFactoid } from './classes/UploadTimeFactoid.ts';
export { default as UpsellDialog } from './classes/UpsellDialog.ts';
export { default as VerticalList } from './classes/VerticalList.ts';
export { default as VerticalWatchCardList } from './classes/VerticalWatchCardList.ts';
@@ -361,10 +374,12 @@ export { default as VideoCard } from './classes/VideoCard.ts';
export { default as VideoDescriptionHeader } from './classes/VideoDescriptionHeader.ts';
export { default as VideoDescriptionInfocardsSection } from './classes/VideoDescriptionInfocardsSection.ts';
export { default as VideoDescriptionMusicSection } from './classes/VideoDescriptionMusicSection.ts';
+export { default as VideoDescriptionTranscriptSection } from './classes/VideoDescriptionTranscriptSection.ts';
export { default as VideoInfoCardContent } from './classes/VideoInfoCardContent.ts';
export { default as VideoOwner } from './classes/VideoOwner.ts';
export { default as VideoPrimaryInfo } from './classes/VideoPrimaryInfo.ts';
export { default as VideoSecondaryInfo } from './classes/VideoSecondaryInfo.ts';
+export { default as ViewCountFactoid } from './classes/ViewCountFactoid.ts';
export { default as WatchCardCompactVideo } from './classes/WatchCardCompactVideo.ts';
export { default as WatchCardHeroVideo } from './classes/WatchCardHeroVideo.ts';
export { default as WatchCardRichHeader } from './classes/WatchCardRichHeader.ts';
diff --git a/deno/src/parser/parser.ts b/deno/src/parser/parser.ts
index 97bd9514..1b22a066 100644
--- a/deno/src/parser/parser.ts
+++ b/deno/src/parser/parser.ts
@@ -7,6 +7,7 @@ import PlayerLiveStoryboardSpec from './classes/PlayerLiveStoryboardSpec.ts';
import PlayerStoryboardSpec from './classes/PlayerStoryboardSpec.ts';
import Alert from './classes/Alert.ts';
import AlertWithButton from './classes/AlertWithButton.ts';
+import EngagementPanelSectionList from './classes/EngagementPanelSectionList.ts';
import type { IParsedResponse, IRawResponse, RawData, RawNode } from './types/index.ts';
@@ -21,7 +22,13 @@ import { Memo, observe, SuperParsedResult } from './helpers.ts';
import * as YTNodes from './nodes.ts';
import type { KeyInfo } from './generator.ts';
import { camelToSnake, generateRuntimeClass, generateTypescriptClass } from './generator.ts';
-import { Continuation, ItemSectionContinuation, SectionListContinuation, LiveChatContinuation, MusicPlaylistShelfContinuation, MusicShelfContinuation, GridContinuation, PlaylistPanelContinuation, NavigateAction, ShowMiniplayerCommand, ReloadContinuationItemsCommand } from './continuations.ts';
+
+import {
+ Continuation, ItemSectionContinuation, SectionListContinuation,
+ LiveChatContinuation, MusicPlaylistShelfContinuation, MusicShelfContinuation,
+ GridContinuation, PlaylistPanelContinuation, NavigateAction, ShowMiniplayerCommand,
+ ReloadContinuationItemsCommand
+} from './continuations.ts';
export type ParserError = {
classname: string,
@@ -289,6 +296,14 @@ export function parseResponse(data:
}
_clearMemo();
+ _createMemo();
+ const items = parse(data.items);
+ if (items) {
+ parsed_data.items = items;
+ parsed_data.items_memo = _getMemo();
+ }
+ _clearMemo();
+
applyMutations(contents_memo, data.frameworkUpdates?.entityBatchUpdate?.mutations);
const continuation = data.continuation ? parseC(data.continuation) : null;
@@ -404,20 +419,10 @@ export function parseResponse(data:
parsed_data.cards = cards;
}
- const engagement_panels = data.engagementPanels?.map((e) => {
- const item = parseItem(e, YTNodes.EngagementPanelSectionList) as YTNodes.EngagementPanelSectionList;
- return item;
- });
- if (engagement_panels) {
+ const engagement_panels = parseArray(data.engagementPanels, EngagementPanelSectionList);
+ if (engagement_panels.length) {
parsed_data.engagement_panels = engagement_panels;
}
- _createMemo();
- const items = parse(data.items);
- if (items) {
- parsed_data.items = items;
- parsed_data.items_memo = _getMemo();
- }
- _clearMemo();
return parsed_data;
}
@@ -429,7 +434,7 @@ export function parseResponse(data:
*/
export function parseItem[]>(data: RawNode | undefined, validTypes: K): InstanceType | null;
export function parseItem(data: RawNode | undefined, validTypes: YTNodeConstructor): T | null;
-export function parseItem(data?: RawNode) : YTNode;
+export function parseItem(data?: RawNode): YTNode;
export function parseItem(data?: RawNode, validTypes?: YTNodeConstructor | YTNodeConstructor[]) {
if (!data) return null;
diff --git a/deno/src/parser/types/ParsedResponse.ts b/deno/src/parser/types/ParsedResponse.ts
index a685a9ad..e12429fb 100644
--- a/deno/src/parser/types/ParsedResponse.ts
+++ b/deno/src/parser/types/ParsedResponse.ts
@@ -20,6 +20,7 @@ import type NavigationEndpoint from '../classes/NavigationEndpoint.ts';
import type PlayerAnnotationsExpanded from '../classes/PlayerAnnotationsExpanded.ts';
import type EngagementPanelSectionList from '../classes/EngagementPanelSectionList.ts';
import type { AppendContinuationItemsAction } from '../nodes.ts';
+
export interface IParsedResponse {
actions?: SuperParsedResult;
actions_memo?: Memo;
@@ -63,7 +64,7 @@ export interface IParsedResponse {
storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec;
endscreen?: Endscreen;
cards?: CardCollection;
- engagement_panels?: EngagementPanelSectionList[];
+ engagement_panels?: ObservedArray;
items?: SuperParsedResult;
}
@@ -106,7 +107,7 @@ export interface INextResponse {
on_response_received_endpoints?: ObservedArray;
on_response_received_endpoints_memo?: Memo;
player_overlays?: SuperParsedResult;
- engagement_panels?: EngagementPanelSectionList[];
+ engagement_panels?: ObservedArray;
}
export interface IBrowseResponse {
@@ -145,6 +146,11 @@ export interface IResolveURLResponse {
endpoint: NavigationEndpoint;
}
+export interface IGetTranscriptResponse {
+ actions: SuperParsedResult;
+ actions_memo: Memo;
+}
+
export interface IGetNotificationsMenuResponse {
actions: SuperParsedResult;
actions_memo: Memo;
diff --git a/deno/src/types/Endpoints.ts b/deno/src/types/Endpoints.ts
index b34dda3b..b732373e 100644
--- a/deno/src/types/Endpoints.ts
+++ b/deno/src/types/Endpoints.ts
@@ -334,18 +334,22 @@ export type EditPlaylistEndpointOptions = {
* The changes to make to the playlist.
*/
actions: {
- action: 'ACTION_ADD_VIDEO' | 'ACTION_REMOVE_VIDEO' | 'ACTION_MOVE_VIDEO_AFTER';
+ action: 'ACTION_ADD_VIDEO' | 'ACTION_REMOVE_VIDEO' | 'ACTION_MOVE_VIDEO_AFTER' | 'ACTION_SET_PLAYLIST_DESCRIPTION' | 'ACTION_SET_PLAYLIST_NAME';
added_video_id?: string;
set_video_id?: string;
moved_set_video_id_predecessor?: string;
+ playlist_description?: string;
+ playlist_name?: string;
}[];
}
export interface IEditPlaylistRequest extends ObjectSnakeToCamel {
actions: {
- action: 'ACTION_ADD_VIDEO' | 'ACTION_REMOVE_VIDEO' | 'ACTION_MOVE_VIDEO_AFTER';
+ action: 'ACTION_ADD_VIDEO' | 'ACTION_REMOVE_VIDEO' | 'ACTION_MOVE_VIDEO_AFTER' | 'ACTION_SET_PLAYLIST_DESCRIPTION' | 'ACTION_SET_PLAYLIST_NAME';
addedVideoId?: string;
setVideoId?: string;
movedSetVideoIdPredecessor?: string;
+ playlistDescription?: string;
+ playlistName?: string;
}[];
}
\ No newline at end of file