mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-07-04 12:47:04 +00:00
feat: Add support for retrieving transcripts (#500)
* feat: Add support for retrieving transcripts * chore: lint * chore: update docs * chore: Do not include nodes in errors thrown * chore: Improve error messages * fix(ExpandableMetadata): `expanded_content` type mismatch * chore: lint
This commit is contained in:
@@ -14,6 +14,8 @@ import NotificationsMenu from './parser/youtube/NotificationsMenu.js';
|
||||
import Playlist from './parser/youtube/Playlist.js';
|
||||
import Search from './parser/youtube/Search.js';
|
||||
import VideoInfo from './parser/youtube/VideoInfo.js';
|
||||
import ContinuationItem from './parser/classes/ContinuationItem.js';
|
||||
import Transcript from './parser/classes/Transcript.js';
|
||||
|
||||
import { Kids, Music, Studio } from './core/clients/index.js';
|
||||
import { AccountManager, InteractionManager, PlaylistManager } from './core/managers/index.js';
|
||||
@@ -36,7 +38,7 @@ import {
|
||||
import { GetUnseenCountEndpoint } from './core/endpoints/notification/index.js';
|
||||
|
||||
import type { ApiResponse } from './core/Actions.js';
|
||||
import type { IBrowseResponse, IParsedResponse } from './parser/types/index.js';
|
||||
import { type IGetTranscriptResponse, type IBrowseResponse, type IParsedResponse } from './parser/types/index.js';
|
||||
import type { INextRequest } from './types/index.js';
|
||||
import type { DownloadOptions, FormatOptions } from './types/FormatUtils.js';
|
||||
|
||||
@@ -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<Transcript> {
|
||||
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<IGetTranscriptResponse>(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}.
|
||||
|
||||
@@ -3,6 +3,7 @@ import Parser, { type RawNode } from '../index.js';
|
||||
import ContinuationItem from './ContinuationItem.js';
|
||||
import EngagementPanelTitleHeader from './EngagementPanelTitleHeader.js';
|
||||
import MacroMarkersList from './MacroMarkersList.js';
|
||||
import ProductList from './ProductList.js';
|
||||
import SectionList from './SectionList.js';
|
||||
import StructuredDescriptionContent from './StructuredDescriptionContent.js';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { YTNode } from '../helpers.js';
|
||||
import Parser, { type RawNode } from '../index.js';
|
||||
import Button from './Button.js';
|
||||
import HorizontalCardList from './HorizontalCardList.js';
|
||||
import HorizontalList from './HorizontalList.js';
|
||||
import Text from './misc/Text.js';
|
||||
import Thumbnail from './misc/Thumbnail.js';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
16
src/parser/classes/FancyDismissibleDialog.ts
Normal file
16
src/parser/classes/FancyDismissibleDialog.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
15
src/parser/classes/ProductList.ts
Normal file
15
src/parser/classes/ProductList.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { ObservedArray} from '../helpers.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
|
||||
export default class ProductList extends YTNode {
|
||||
static type = 'ProductList';
|
||||
|
||||
contents: ObservedArray<YTNode>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.contents = Parser.parseArray(data.contents);
|
||||
}
|
||||
}
|
||||
16
src/parser/classes/ProductListHeader.ts
Normal file
16
src/parser/classes/ProductListHeader.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
31
src/parser/classes/ProductListItem.ts
Normal file
31
src/parser/classes/ProductListItem.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import { Text, Thumbnail } from '../misc.js';
|
||||
import Button from './Button.js';
|
||||
import NavigationEndpoint from './NavigationEndpoint.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,15 @@ import HorizontalCardList from './HorizontalCardList.js';
|
||||
import VideoDescriptionHeader from './VideoDescriptionHeader.js';
|
||||
import VideoDescriptionInfocardsSection from './VideoDescriptionInfocardsSection.js';
|
||||
import VideoDescriptionMusicSection from './VideoDescriptionMusicSection.js';
|
||||
import type VideoDescriptionTranscriptSection from './VideoDescriptionTranscriptSection.js';
|
||||
|
||||
export default class StructuredDescriptionContent extends YTNode {
|
||||
static type = 'StructuredDescriptionContent';
|
||||
|
||||
items: ObservedArray<VideoDescriptionHeader | ExpandableVideoDescriptionBody | VideoDescriptionMusicSection | VideoDescriptionInfocardsSection | HorizontalCardList>;
|
||||
items: ObservedArray<
|
||||
VideoDescriptionHeader | ExpandableVideoDescriptionBody | VideoDescriptionMusicSection |
|
||||
VideoDescriptionInfocardsSection | VideoDescriptionTranscriptSection | HorizontalCardList
|
||||
>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
15
src/parser/classes/Transcript.ts
Normal file
15
src/parser/classes/Transcript.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import TranscriptSearchPanel from './TranscriptSearchPanel.js';
|
||||
|
||||
export default class Transcript extends YTNode {
|
||||
static type = 'Transcript';
|
||||
|
||||
content: TranscriptSearchPanel | null;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.content = Parser.parseItem(data.content, TranscriptSearchPanel);
|
||||
}
|
||||
}
|
||||
15
src/parser/classes/TranscriptFooter.ts
Normal file
15
src/parser/classes/TranscriptFooter.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import SortFilterSubMenu from './SortFilterSubMenu.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
23
src/parser/classes/TranscriptSearchBox.ts
Normal file
23
src/parser/classes/TranscriptSearchBox.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import Button from './Button.js';
|
||||
import NavigationEndpoint from './NavigationEndpoint.js';
|
||||
import { Text } from '../misc.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
23
src/parser/classes/TranscriptSearchPanel.ts
Normal file
23
src/parser/classes/TranscriptSearchPanel.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import TranscriptFooter from './TranscriptFooter.js';
|
||||
import TranscriptSearchBox from './TranscriptSearchBox.js';
|
||||
import TranscriptSegmentList from './TranscriptSegmentList.js';
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
22
src/parser/classes/TranscriptSegment.ts
Normal file
22
src/parser/classes/TranscriptSegment.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
23
src/parser/classes/TranscriptSegmentList.ts
Normal file
23
src/parser/classes/TranscriptSegmentList.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { ObservedArray} from '../helpers.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
import TranscriptSegment from './TranscriptSegment.js';
|
||||
|
||||
export default class TranscriptSegmentList extends YTNode {
|
||||
static type = 'TranscriptSegmentList';
|
||||
|
||||
initial_segments: ObservedArray<TranscriptSegment>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
15
src/parser/classes/UploadTimeFactoid.ts
Normal file
15
src/parser/classes/UploadTimeFactoid.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import Factoid from './Factoid.js';
|
||||
|
||||
export default class UploadTimeFactoid extends YTNode {
|
||||
static type = 'UploadTimeFactoid';
|
||||
|
||||
factoid: Factoid | null;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.factoid = Parser.parseItem(data.factoid, Factoid);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import Parser, { type RawNode } from '../index.js';
|
||||
import { Text, Thumbnail } from '../misc.js';
|
||||
import Factoid from './Factoid.js';
|
||||
import NavigationEndpoint from './NavigationEndpoint.js';
|
||||
import UploadTimeFactoid from './UploadTimeFactoid.js';
|
||||
import ViewCountFactoid from './ViewCountFactoid.js';
|
||||
|
||||
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<Factoid>;
|
||||
factoids: ObservedArray<Factoid | ViewCountFactoid | UploadTimeFactoid>;
|
||||
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 ]);
|
||||
}
|
||||
}
|
||||
|
||||
20
src/parser/classes/VideoDescriptionTranscriptSection.ts
Normal file
20
src/parser/classes/VideoDescriptionTranscriptSection.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
import Button from './Button.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
19
src/parser/classes/ViewCountFactoid.ts
Normal file
19
src/parser/classes/ViewCountFactoid.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import Parser from '../index.js';
|
||||
import Factoid from './Factoid.js';
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
17
src/parser/classes/actions/UpdateEngagementPanelAction.ts
Normal file
17
src/parser/classes/actions/UpdateEngagementPanelAction.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { YTNode } from '../../helpers.js';
|
||||
import type { RawNode } from '../../index.js';
|
||||
import Parser from '../../index.js';
|
||||
import Transcript from '../Transcript.js';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
17
src/parser/classes/menus/MenuPopup.ts
Normal file
17
src/parser/classes/menus/MenuPopup.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { ObservedArray} from '../../helpers.js';
|
||||
import { YTNode } from '../../helpers.js';
|
||||
import type { RawNode } from '../../index.js';
|
||||
import Parser from '../../index.js';
|
||||
import MenuNavigationItem from './MenuNavigationItem.js';
|
||||
import MenuServiceItem from './MenuServiceItem.js';
|
||||
|
||||
export default class MenuPopup extends YTNode {
|
||||
static type = 'MenuPopup';
|
||||
|
||||
items: ObservedArray<MenuNavigationItem | MenuServiceItem>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.items = Parser.parseArray(data.items, [ MenuNavigationItem, MenuServiceItem ]);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export { default as AccountItemSectionHeader } from './classes/AccountItemSectio
|
||||
export { default as AccountSectionList } from './classes/AccountSectionList.js';
|
||||
export { default as AppendContinuationItemsAction } from './classes/actions/AppendContinuationItemsAction.js';
|
||||
export { default as OpenPopupAction } from './classes/actions/OpenPopupAction.js';
|
||||
export { default as UpdateEngagementPanelAction } from './classes/actions/UpdateEngagementPanelAction.js';
|
||||
export { default as Alert } from './classes/Alert.js';
|
||||
export { default as AlertWithButton } from './classes/AlertWithButton.js';
|
||||
export { default as AnalyticsMainAppKeyMetrics } from './classes/analytics/AnalyticsMainAppKeyMetrics.js';
|
||||
@@ -102,6 +103,7 @@ export { default as ExpandableTab } from './classes/ExpandableTab.js';
|
||||
export { default as ExpandableVideoDescriptionBody } from './classes/ExpandableVideoDescriptionBody.js';
|
||||
export { default as ExpandedShelfContents } from './classes/ExpandedShelfContents.js';
|
||||
export { default as Factoid } from './classes/Factoid.js';
|
||||
export { default as FancyDismissibleDialog } from './classes/FancyDismissibleDialog.js';
|
||||
export { default as FeedFilterChipBar } from './classes/FeedFilterChipBar.js';
|
||||
export { default as FeedTabbedHeader } from './classes/FeedTabbedHeader.js';
|
||||
export { default as GameCard } from './classes/GameCard.js';
|
||||
@@ -191,6 +193,7 @@ export { default as MacroMarkersList } from './classes/MacroMarkersList.js';
|
||||
export { default as MacroMarkersListItem } from './classes/MacroMarkersListItem.js';
|
||||
export { default as Menu } from './classes/menus/Menu.js';
|
||||
export { default as MenuNavigationItem } from './classes/menus/MenuNavigationItem.js';
|
||||
export { default as MenuPopup } from './classes/menus/MenuPopup.js';
|
||||
export { default as MenuServiceItem } from './classes/menus/MenuServiceItem.js';
|
||||
export { default as MenuServiceItemDownload } from './classes/menus/MenuServiceItemDownload.js';
|
||||
export { default as MultiPageMenu } from './classes/menus/MultiPageMenu.js';
|
||||
@@ -274,6 +277,9 @@ export { default as PlaylistVideoThumbnail } from './classes/PlaylistVideoThumbn
|
||||
export { default as Poll } from './classes/Poll.js';
|
||||
export { default as Post } from './classes/Post.js';
|
||||
export { default as PostMultiImage } from './classes/PostMultiImage.js';
|
||||
export { default as ProductList } from './classes/ProductList.js';
|
||||
export { default as ProductListHeader } from './classes/ProductListHeader.js';
|
||||
export { default as ProductListItem } from './classes/ProductListItem.js';
|
||||
export { default as ProfileColumn } from './classes/ProfileColumn.js';
|
||||
export { default as ProfileColumnStats } from './classes/ProfileColumnStats.js';
|
||||
export { default as ProfileColumnStatsEntry } from './classes/ProfileColumnStatsEntry.js';
|
||||
@@ -349,10 +355,17 @@ export { default as ToggleButton } from './classes/ToggleButton.js';
|
||||
export { default as ToggleMenuServiceItem } from './classes/ToggleMenuServiceItem.js';
|
||||
export { default as Tooltip } from './classes/Tooltip.js';
|
||||
export { default as TopicChannelDetails } from './classes/TopicChannelDetails.js';
|
||||
export { default as Transcript } from './classes/Transcript.js';
|
||||
export { default as TranscriptFooter } from './classes/TranscriptFooter.js';
|
||||
export { default as TranscriptSearchBox } from './classes/TranscriptSearchBox.js';
|
||||
export { default as TranscriptSearchPanel } from './classes/TranscriptSearchPanel.js';
|
||||
export { default as TranscriptSegment } from './classes/TranscriptSegment.js';
|
||||
export { default as TranscriptSegmentList } from './classes/TranscriptSegmentList.js';
|
||||
export { default as TwoColumnBrowseResults } from './classes/TwoColumnBrowseResults.js';
|
||||
export { default as TwoColumnSearchResults } from './classes/TwoColumnSearchResults.js';
|
||||
export { default as TwoColumnWatchNextResults } from './classes/TwoColumnWatchNextResults.js';
|
||||
export { default as UniversalWatchCard } from './classes/UniversalWatchCard.js';
|
||||
export { default as UploadTimeFactoid } from './classes/UploadTimeFactoid.js';
|
||||
export { default as UpsellDialog } from './classes/UpsellDialog.js';
|
||||
export { default as VerticalList } from './classes/VerticalList.js';
|
||||
export { default as VerticalWatchCardList } from './classes/VerticalWatchCardList.js';
|
||||
@@ -361,10 +374,12 @@ export { default as VideoCard } from './classes/VideoCard.js';
|
||||
export { default as VideoDescriptionHeader } from './classes/VideoDescriptionHeader.js';
|
||||
export { default as VideoDescriptionInfocardsSection } from './classes/VideoDescriptionInfocardsSection.js';
|
||||
export { default as VideoDescriptionMusicSection } from './classes/VideoDescriptionMusicSection.js';
|
||||
export { default as VideoDescriptionTranscriptSection } from './classes/VideoDescriptionTranscriptSection.js';
|
||||
export { default as VideoInfoCardContent } from './classes/VideoInfoCardContent.js';
|
||||
export { default as VideoOwner } from './classes/VideoOwner.js';
|
||||
export { default as VideoPrimaryInfo } from './classes/VideoPrimaryInfo.js';
|
||||
export { default as VideoSecondaryInfo } from './classes/VideoSecondaryInfo.js';
|
||||
export { default as ViewCountFactoid } from './classes/ViewCountFactoid.js';
|
||||
export { default as WatchCardCompactVideo } from './classes/WatchCardCompactVideo.js';
|
||||
export { default as WatchCardHeroVideo } from './classes/WatchCardHeroVideo.js';
|
||||
export { default as WatchCardRichHeader } from './classes/WatchCardRichHeader.js';
|
||||
|
||||
@@ -7,6 +7,7 @@ import PlayerLiveStoryboardSpec from './classes/PlayerLiveStoryboardSpec.js';
|
||||
import PlayerStoryboardSpec from './classes/PlayerStoryboardSpec.js';
|
||||
import Alert from './classes/Alert.js';
|
||||
import AlertWithButton from './classes/AlertWithButton.js';
|
||||
import EngagementPanelSectionList from './classes/EngagementPanelSectionList.js';
|
||||
|
||||
import type { IParsedResponse, IRawResponse, RawData, RawNode } from './types/index.js';
|
||||
|
||||
@@ -21,7 +22,13 @@ import { Memo, observe, SuperParsedResult } from './helpers.js';
|
||||
import * as YTNodes from './nodes.js';
|
||||
import type { KeyInfo } from './generator.js';
|
||||
import { camelToSnake, generateRuntimeClass, generateTypescriptClass } from './generator.js';
|
||||
import { Continuation, ItemSectionContinuation, SectionListContinuation, LiveChatContinuation, MusicPlaylistShelfContinuation, MusicShelfContinuation, GridContinuation, PlaylistPanelContinuation, NavigateAction, ShowMiniplayerCommand, ReloadContinuationItemsCommand } from './continuations.js';
|
||||
|
||||
import {
|
||||
Continuation, ItemSectionContinuation, SectionListContinuation,
|
||||
LiveChatContinuation, MusicPlaylistShelfContinuation, MusicShelfContinuation,
|
||||
GridContinuation, PlaylistPanelContinuation, NavigateAction, ShowMiniplayerCommand,
|
||||
ReloadContinuationItemsCommand
|
||||
} from './continuations.js';
|
||||
|
||||
export type ParserError = {
|
||||
classname: string,
|
||||
@@ -289,6 +296,14 @@ export function parseResponse<T extends IParsedResponse = IParsedResponse>(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<T extends IParsedResponse = IParsedResponse>(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<T extends IParsedResponse = IParsedResponse>(data:
|
||||
*/
|
||||
export function parseItem<T extends YTNode, K extends YTNodeConstructor<T>[]>(data: RawNode | undefined, validTypes: K): InstanceType<K[number]> | null;
|
||||
export function parseItem<T extends YTNode>(data: RawNode | undefined, validTypes: YTNodeConstructor<T>): 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;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import type NavigationEndpoint from '../classes/NavigationEndpoint.js';
|
||||
import type PlayerAnnotationsExpanded from '../classes/PlayerAnnotationsExpanded.js';
|
||||
import type EngagementPanelSectionList from '../classes/EngagementPanelSectionList.js';
|
||||
import type { AppendContinuationItemsAction } from '../nodes.js';
|
||||
|
||||
export interface IParsedResponse {
|
||||
actions?: SuperParsedResult<YTNode>;
|
||||
actions_memo?: Memo;
|
||||
@@ -63,7 +64,7 @@ export interface IParsedResponse {
|
||||
storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec;
|
||||
endscreen?: Endscreen;
|
||||
cards?: CardCollection;
|
||||
engagement_panels?: EngagementPanelSectionList[];
|
||||
engagement_panels?: ObservedArray<EngagementPanelSectionList>;
|
||||
items?: SuperParsedResult<YTNode>;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ export interface INextResponse {
|
||||
on_response_received_endpoints?: ObservedArray<ReloadContinuationItemsCommand | AppendContinuationItemsAction>;
|
||||
on_response_received_endpoints_memo?: Memo;
|
||||
player_overlays?: SuperParsedResult<YTNode>;
|
||||
engagement_panels?: EngagementPanelSectionList[];
|
||||
engagement_panels?: ObservedArray<EngagementPanelSectionList>;
|
||||
}
|
||||
|
||||
export interface IBrowseResponse {
|
||||
@@ -145,6 +146,11 @@ export interface IResolveURLResponse {
|
||||
endpoint: NavigationEndpoint;
|
||||
}
|
||||
|
||||
export interface IGetTranscriptResponse {
|
||||
actions: SuperParsedResult<YTNode>;
|
||||
actions_memo: Memo;
|
||||
}
|
||||
|
||||
export interface IGetNotificationsMenuResponse {
|
||||
actions: SuperParsedResult<YTNode>;
|
||||
actions_memo: Memo;
|
||||
|
||||
Reference in New Issue
Block a user