From e1de9123c0101d08013ec4d58757ba1dec650837 Mon Sep 17 00:00:00 2001 From: Nico K Date: Fri, 3 Mar 2023 05:32:06 +0100 Subject: [PATCH] Add support for `game_info` to `getInfo()` and `category` to `getBasicInfo()` --- src/parser/classes/RichMetadata.ts | 32 +++++++++++++++++++++++++++ src/parser/classes/RichMetadataRow.ts | 15 +++++++++++++ src/parser/map.ts | 6 +++++ src/parser/youtube/VideoInfo.ts | 14 ++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/parser/classes/RichMetadata.ts create mode 100644 src/parser/classes/RichMetadataRow.ts diff --git a/src/parser/classes/RichMetadata.ts b/src/parser/classes/RichMetadata.ts new file mode 100644 index 000000000..76dc7b1e2 --- /dev/null +++ b/src/parser/classes/RichMetadata.ts @@ -0,0 +1,32 @@ +import Text from './misc/Text.js'; +import Thumbnail from './misc/Thumbnail.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; +import { YTNode } from '../helpers.js'; + +class RichMetadata extends YTNode { + static type = 'RichMetadata'; + + thumbnail: Thumbnail[]; + title: Text; + subtitle?: Text; + call_to_action: Text; + icon_type?: string; + endpoint: NavigationEndpoint; + + constructor(data: any) { + super(); + + this.thumbnail = Thumbnail.fromResponse(data.thumbnail); + this.title = new Text(data.title); + this.subtitle = new Text(data.subtitle); + this.call_to_action = new Text(data.callToAction); + + if (data.callToActionIcon?.iconType) { + this.icon_type = data.callToActionIcon?.iconType; + } + + this.endpoint = new NavigationEndpoint(data.endpoint); + } +} + +export default RichMetadata; \ No newline at end of file diff --git a/src/parser/classes/RichMetadataRow.ts b/src/parser/classes/RichMetadataRow.ts new file mode 100644 index 000000000..189b8f4cc --- /dev/null +++ b/src/parser/classes/RichMetadataRow.ts @@ -0,0 +1,15 @@ +import Parser from '../index.js'; +import { YTNode } from '../helpers.js'; + +class RichMetadataRow extends YTNode { + static type = 'RichMetadataRow'; + + contents; + + constructor(data: any) { + super(); + this.contents = Parser.parseArray(data.contents); + } +} + +export default RichMetadataRow; \ No newline at end of file diff --git a/src/parser/map.ts b/src/parser/map.ts index ecbbe52da..b4094b1a0 100644 --- a/src/parser/map.ts +++ b/src/parser/map.ts @@ -500,6 +500,10 @@ import { default as RichItem } from './classes/RichItem.js'; export { RichItem }; import { default as RichListHeader } from './classes/RichListHeader.js'; export { RichListHeader }; +import { default as RichMetadata } from './classes/RichMetadata.js'; +export { RichMetadata }; +import { default as RichMetadataRow } from './classes/RichMetadataRow.js'; +export { RichMetadataRow }; import { default as RichSection } from './classes/RichSection.js'; export { RichSection }; import { default as RichShelf } from './classes/RichShelf.js'; @@ -898,6 +902,8 @@ const map: Record = { RichGrid, RichItem, RichListHeader, + RichMetadata, + RichMetadataRow, RichSection, RichShelf, SearchBox, diff --git a/src/parser/youtube/VideoInfo.ts b/src/parser/youtube/VideoInfo.ts index 5b43bde87..f17c66d06 100644 --- a/src/parser/youtube/VideoInfo.ts +++ b/src/parser/youtube/VideoInfo.ts @@ -12,6 +12,8 @@ import MicroformatData from '../classes/MicroformatData.js'; import PlayerMicroformat from '../classes/PlayerMicroformat.js'; import PlayerOverlay from '../classes/PlayerOverlay.js'; import RelatedChipCloud from '../classes/RelatedChipCloud.js'; +import RichMetadata from '../classes/RichMetadata.js'; +import RichMetadataRow from '../classes/RichMetadataRow.js'; import SegmentedLikeDislikeButton from '../classes/SegmentedLikeDislikeButton.js'; import ToggleButton from '../classes/ToggleButton.js'; import TwoColumnWatchNextResults from '../classes/TwoColumnWatchNextResults.js'; @@ -58,6 +60,7 @@ class VideoInfo { primary_info?: VideoPrimaryInfo | null; secondary_info?: VideoSecondaryInfo | null; + game_info?; merchandise?: MerchandiseShelf | null; related_chip_cloud?: ChipCloud | null; watch_next_feed?: ObservedArray | null; @@ -98,6 +101,7 @@ class VideoInfo { channel: info.microformat?.is(PlayerMicroformat) ? info.microformat?.channel : null, is_unlisted: info.microformat?.is_unlisted, is_family_safe: info.microformat?.is_family_safe, + category: info.microformat?.is(PlayerMicroformat) ? info.microformat?.category : null, has_ypc_metadata: info.microformat?.is(PlayerMicroformat) ? info.microformat?.has_ypc_metadata : null, start_timestamp: info.microformat?.is(PlayerMicroformat) ? info.microformat.start_timestamp : null }, @@ -122,6 +126,16 @@ class VideoInfo { const secondary_results = two_col?.secondary_results; if (results && secondary_results) { + if (info.microformat?.is(PlayerMicroformat) && info.microformat?.category === 'Gaming') { + const row = results.firstOfType(VideoSecondaryInfo)?.metadata?.rows?.firstOfType(RichMetadataRow); + if (row?.is(RichMetadataRow)) { + this.game_info = { + title: row?.contents?.firstOfType(RichMetadata)?.title, + release_year: row?.contents?.firstOfType(RichMetadata)?.subtitle + }; + } + } + this.primary_info = results.firstOfType(VideoPrimaryInfo); this.secondary_info = results.firstOfType(VideoSecondaryInfo); this.merchandise = results.firstOfType(MerchandiseShelf);