mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-28 09:06:51 +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:
@@ -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 ]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user