diff --git a/.gitignore b/.gitignore index 75cee5edc..8deca85bc 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,8 @@ jspm_packages/ .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +# pnpm +.pnpm-debug.log* +pnpm-lock.yaml diff --git a/examples/channel.js b/examples/channel.js new file mode 100644 index 000000000..a93d6abf4 --- /dev/null +++ b/examples/channel.js @@ -0,0 +1,39 @@ +const Innertube = require('..'); + +(async () => { + +const session = await new Innertube(); + +const channel = await session.getChannel('UCX6OQ3DkcsbYNE6H8uQQuVA'); + +console.log('Viewing channel:', channel.title); +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); +} + +console.log('\nLists the following playlists:'); +const playlists = await channel.getPlaylists(); +for (const playlist of playlists.playlists) { + console.log('Playlist:', playlist.title); +} + +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.backstage_posts) { + console.log('Backstage post:', post.content.toString().substring(0, 20) + '...'); +} + +})(); \ No newline at end of file diff --git a/examples/index.js b/examples/index.js index 8779b4fd0..9709de2bb 100644 --- a/examples/index.js +++ b/examples/index.js @@ -5,6 +5,9 @@ const Innertube = require('..'); const creds_path = './yt_oauth_creds.json'; const creds = fs.existsSync(creds_path) && JSON.parse(fs.readFileSync(creds_path).toString()) || {}; +/** + * + */ async function start() { const youtube = await new Innertube(); diff --git a/lib/Innertube.js b/lib/Innertube.js index 940e800df..ba19cfe74 100644 --- a/lib/Innertube.js +++ b/lib/Innertube.js @@ -25,6 +25,10 @@ const Constants = require('./utils/Constants'); const Proto = require('./proto'); const NToken = require('./deciphers/NToken'); const Signature = require('./deciphers/Signature'); +const Channel = require('./parser/youtube/Channel'); +const Playlist = require('./parser/youtube/Playlist'); +const FilterableFeed = require('./core/FilterableFeed'); +const TabbedFeed = require('./core/TabbedFeed'); class Innertube { #axios; @@ -187,7 +191,7 @@ class Innertube { Utils.throwIfMissing({ query }); const response = await this.actions.search({ query, filters }); - return new Search(response, this.actions); + return new Search(this.actions, response.data); } /** @@ -228,7 +232,7 @@ class Innertube { } /** - * Retrieves comments for a given video. + * Retrieves comments for a video. * * @param {string} video_id - the video id. * @param {string} [sort_by] - can be: `TOP_COMMENTS` or `NEWEST_FIRST`. @@ -255,19 +259,14 @@ class Innertube { * Retrieves contents for a given channel. (WIP) * * @param {string} id - channel id - * @returns {Promise.<{ title: string, description: string, metadata: object, content: object }>} + * @returns {Promise} */ async getChannel(id) { Utils.throwIfMissing({ id }); const response = await this.actions.browse(id); - - const channel_info = new Parser(this, response.data, { - client: 'YOUTUBE', - data_type: 'CHANNEL' - }).parse(); - return channel_info; + return new Channel(response.data, this.actions); } /** @@ -287,37 +286,27 @@ class Innertube { } /** - * Retrieves home feed (aka recommendations). + * Retrieves YouTube's home feed (aka recommendations). * - * @returns {Promise.<{ videos: Array.<{ id: string, title: string, description: string, channel: string, metadata: object }>}>} + * @returns {Promise} */ async getHomeFeed() { const response = await this.actions.browse('FEwhat_to_watch'); + if (!response.success) throw new Utils.InnertubeError('Could not retrieve home feed', response); - const homefeed = new Parser(this, response, { - client: 'YOUTUBE', - data_type: 'HOMEFEED' - }).parse(); - - return homefeed; + return new FilterableFeed(this.actions, response.data); } /** * Retrieves trending content. - * - * @returns {Promise.<{ now: { content: Array.<{ title: string, videos: object[] }> }, - * music: { getVideos: Promise.> }, gaming: { getVideos: Promise.> }, - * movies: { getVideos: Promise.> } }>} + * + * @returns {Promise} */ async getTrending() { const response = await this.actions.browse('FEtrending'); - - const trending = new Parser(this, response, { - client: 'YOUTUBE', - data_type: 'TRENDING' - }).parse(); + if (!response.success) throw new Utils.InnertubeError('Could not retrieve trending content', response); - return trending; + return new TabbedFeed(this.actions, response.data); } /** @@ -408,14 +397,11 @@ class Innertube { */ async getPlaylist(playlist_id, options = { client: 'YOUTUBE' }) { Utils.throwIfMissing({ playlist_id }); - + const response = await this.actions.browse(`VL${playlist_id}`, { client: options.client }); - const playlist = new Parser(this, response.data, { - client: options.client, - data_type: 'PLAYLIST' - }).parse(); + if (!response.success) throw new Utils.InnertubeError('Could not get playlist', response); - return playlist; + return new Playlist(this.actions, response.data); } /** @@ -660,6 +646,10 @@ class Innertube { return stream; } + + getPlayer() { + return this.#player; + } /** @readonly */ get axios() { diff --git a/lib/core/Feed.js b/lib/core/Feed.js new file mode 100644 index 000000000..6a771d851 --- /dev/null +++ b/lib/core/Feed.js @@ -0,0 +1,153 @@ +const ResultsParser = require('../parser/contents'); +const { InnertubeError } = require('../utils/Utils'); + +// TODO: add a way subdivide into sections and return subfeeds? + +class Feed { + #page; + /** + * @type {import('../parser/contents/classes/ContinuationItem')[]} + */ + #continuation; + /** + * @type {import('../core/Actions')} + */ + #actions; + + memo; + constructor(actions, data, already_parsed = false) { + if (data.on_response_received_actions || data.on_response_received_endpoints || already_parsed) + this.#page = data; + else + this.#page = ResultsParser.parseResponse(data); + this.memo = + this.#page.on_response_received_actions ? + this.#page.on_response_received_actions_memo : + this.#page.on_response_received_endpoints ? + this.#page.on_response_received_endpoints_memo : + this.#page.contents_memo; + + this.#actions = actions; + } + + + /** + * Get the original page data + */ + get page() { + return this.#page; + } + + get actions() { + return this.#actions; + } + + /** + * Get all videos on a given page via memo + * + * @param {Map} memo + * @returns {Array} + */ + static getVideosFromMemo(memo) { + const videos = memo.get('Video') || []; + const grid_videos = memo.get('GridVideo') || []; + const compact_videos = memo.get('CompactVideo') || []; + const playlist_videos = memo.get('PlaylistVideo') || []; + const playlist_panel_videos = memo.get('PlaylistPanelVideo') || []; + const watch_card_compact_videos = memo.get('WatchCardCompactVideo') || []; + return [...videos, ...grid_videos, ...compact_videos, ...playlist_videos, ...playlist_panel_videos, ...watch_card_compact_videos]; + } + + /** + * Get all playlists on a given page via memo + * + * @param {Map} memo + * @returns {Array} + */ + static getPlaylistsFromMemo(memo) { + const playlists = memo.get('Playlist') || []; + const grid_playlists = memo.get('GridPlaylist') || []; + return [...playlists, ...grid_playlists]; + } + + /** + * Get all the videos in the feed + */ + get videos() { + return Feed.getVideosFromMemo(this.memo); + } + + /** + * Get all playlists in the feed + * + * @returns {Array} + */ + get playlists() { + return Feed.getPlaylistsFromPage(this.memo); + } + + /** + * Get all the community posts in the feed + * + * @returns {import('../parser/contents/classes/BackstagePost')[]} + */ + get backstage_posts() { + return this.memo.get('BackstagePost'); + } + + /** + * Get all the channels in the feed + * + * @returns {Array} + */ + get channels() { + const channels = this.memo.get('Channel') || []; + const grid_channels = this.memo.get('GridChannel') || []; + return [...channels, ...grid_channels]; + } + + get has_continuation() { + return (this.memo.get('ContinuationItem') || []).length > 0; + } + + async getContinuationData() { + if (this.#continuation) { + if (this.#continuation.length > 1) + throw new InnertubeError('There are too many continuations, you\'ll need to find the correct one yourself in this.page'); + if (this.#continuation.length === 0) + throw new InnertubeError('There are no continuations'); + const continuation = this.#continuation[0]; + return await continuation.endpoint.call(this.#actions); + } + + this.#continuation = this.memo.get('ContinuationItem'); + + if (this.#continuation) + return this.getContinuationData(); + + return null; + } + + get shelves() { + return this.#page.contents_memo.get('Shelf'); + } + + getShelf(title) { + return this.shelves.find(shelf => shelf.title.toString() === title); + } + + get shelf_content() { + return this.shelves.map(shelf => ({ + title: shelf.title.toString(), + content: shelf.content.contents, + })); + } + + async getContinuation() { + const continuation_data = await this.getContinuationData(); + + return new Feed(this.actions, continuation_data, true); + } +} + +module.exports = Feed; diff --git a/lib/core/FilterableFeed.js b/lib/core/FilterableFeed.js new file mode 100644 index 000000000..fcad2165b --- /dev/null +++ b/lib/core/FilterableFeed.js @@ -0,0 +1,49 @@ +const { InnertubeError } = require('../utils/Utils'); +const Feed = require('./Feed'); + +class FilterableFeed extends Feed { + /** + * @type {import('../parser/contents/ChipCloudChip')[]} + */ + #chips; + constructor(actions, data, already_parsed = false) { + super(actions, data, already_parsed) + } + + /** + * Get filters for the feed + * + * @returns {import('../parser/contents/ChipCloudChip')[]} + */ + get filter_chips() { + if (this.#chips) return this.#chips || []; + + if (this.memo.get('FeedFilterChipBar')?.length > 1) + throw new InnertubeError('There are too many feed filter chipbars, you\'ll need to find the correct one yourself in this.page'); + if (this.memo.get('FeedFilterChipBar')?.length === 0) + throw new InnertubeError('There are no feed filter chipbars'); + + this.#chips = this.memo.get('ChipCloudChip') || []; + + return this.#chips || []; + } + + get filters() { + return this.filter_chips.map(chip => chip.text.toString()) || []; + } + + async getFilteredFeed(name) { + if (!this.filters.includes(name)) + throw new InnertubeError('Invalid filter', { available_filters: this.filters }); + + const filter = this.filter_chips.find(chip => chip.text.toString() === name); + + if (filter.is_selected) return this; + + const response = await filter.endpoint.call(this.actions); + + return new Feed(this.actions, response, true); + } +} + +module.exports = FilterableFeed; \ No newline at end of file diff --git a/lib/core/TabbedFeed.js b/lib/core/TabbedFeed.js new file mode 100644 index 000000000..c8077ed5d --- /dev/null +++ b/lib/core/TabbedFeed.js @@ -0,0 +1,48 @@ +const ResultsParser = require('../parser/contents'); +const { InnertubeError } = require('../utils/Utils'); +const Feed = require('./Feed'); + +class TabbedFeed extends Feed { + #page; + /** + * @type {import('../parser/contents/classes/Tab')[]} + */ + #tabs; + #actions; + constructor (actions, data, already_parsed = false) { + super(actions, data, already_parsed); + this.#actions = actions; + this.#page = already_parsed ? data : ResultsParser.parseResponse(data); + this.#tabs = this.#page.contents_memo.get('Tab'); + } + + get tabs() { + return this.#tabs.map(tab => tab.title.toString()); + } + + /** + * + * @param {string} title title of the tab to get + * @returns {Promise} + */ + async getTab(title) { + const tab = this.#tabs.find(tab => tab.title.toLowerCase() === title.toLowerCase()); + if (!tab) throw new InnertubeError(`Tab "${title}" not found`); + + if (tab.selected) return this; + + const response = await tab.endpoint.call(this.#actions); + + return new TabbedFeed(this.#actions, response, true); + } + + get title() { + return this.#page.contents_memo('Tab')?.find(tab => tab.selected)?.title.toString(); + } + + get page() { + return this.#page; + } +} + +module.exports = TabbedFeed; \ No newline at end of file diff --git a/lib/parser/contents/classes/AnalyticsMainAppKeyMetrics.js b/lib/parser/contents/classes/AnalyticsMainAppKeyMetrics.js index 6f534fc0f..4f4acb7d9 100644 --- a/lib/parser/contents/classes/AnalyticsMainAppKeyMetrics.js +++ b/lib/parser/contents/classes/AnalyticsMainAppKeyMetrics.js @@ -3,7 +3,7 @@ const DataModelSection = require('./DataModelSection'); class AnalyticsMainAppKeyMetrics { - type = 'analyticsMainAppKeyMetricsModel'; + type = 'AnalyticsMainAppKeyMetrics'; constructor(data) { this.period = data.cardData.periodLabel; diff --git a/lib/parser/contents/classes/AnalyticsVideo.js b/lib/parser/contents/classes/AnalyticsVideo.js index 546e808ef..d2eea9df9 100644 --- a/lib/parser/contents/classes/AnalyticsVideo.js +++ b/lib/parser/contents/classes/AnalyticsVideo.js @@ -3,14 +3,14 @@ const Thumbnail = require('../Thumbnail'); class AnalyticsVideo { - type = 'video'; + type = 'AnalyticsVideo'; constructor(data) { this.title = data.videoTitle; this.metadata = { views: data.videoDescription.split('·')[0].trim(), published: data.videoDescription.split('·')[1].trim(), - thumbnails: new Thumbnail(data.thumbnailDetails).thumbnails, + thumbnails: Thumbnail.fromResponse(data.thumbnailDetails), duration: data.formattedLength, is_short: data.isShort } diff --git a/lib/parser/contents/classes/AnalyticsVodCarouselCard.js b/lib/parser/contents/classes/AnalyticsVodCarouselCard.js index b9101f617..dab67b7f0 100644 --- a/lib/parser/contents/classes/AnalyticsVodCarouselCard.js +++ b/lib/parser/contents/classes/AnalyticsVodCarouselCard.js @@ -3,7 +3,7 @@ const Video = require('./AnalyticsVideo'); class AnalyticsVodCarouselCard { - type = 'analyticsVodCarouselCardModel'; + type = 'AnalyticsVodCarouselCard'; constructor(data) { this.title = data.title; diff --git a/lib/parser/contents/classes/Author.js b/lib/parser/contents/classes/Author.js index 6b5e0b619..424509c15 100644 --- a/lib/parser/contents/classes/Author.js +++ b/lib/parser/contents/classes/Author.js @@ -1,22 +1,69 @@ -'use strict'; - -const Text = require('./Text'); -const Constants = require('../../../utils/Constants'); -const MetadataBadge = require('./MetadataBadge'); +const Parser = require('..'); +const NavigatableText = require('./NavigatableText'); +const Thumbnail = require('./Thumbnail'); class Author { - constructor(data) { - const nav_text = new Text(data.nav_text); - const badges = data.badges && data.badges.map((badge) => new MetadataBadge(badge.metadataBadgeRenderer)); - - this.id = nav_text.runs[0].endpoint.browse?.id || 'N/A'; - this.url = nav_text.runs[0].endpoint.browse && `${Constants.URLS.YT_BASE}${nav_text.runs[0].endpoint.browse?.base_url}` || 'N/A'; - this.name = nav_text.text || 'N/A' - this.endpoint = nav_text.runs[0].endpoint; - this.badges = badges || []; - - this.is_verified = badges?.some((badge) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED') || null; - this.is_verified_artist = badges?.some((badge) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED_ARTIST') || null; + #nav_text; + /** + * @type {import('./MetadataBadge')[]} + */ + badges; + /** + * @type {Thumbnail[]} + */ + thumbnails; + constructor(item, badges, thumbs) { + this.#nav_text = new NavigatableText(item); + this.badges = Array.isArray(badges) ? Parser.parse(badges) : []; + if (thumbs) { + this.thumbnails = Thumbnail.fromResponse(thumbs); + } + else { + this.thumbnails = []; + } + } + + get url() { + return this.#nav_text.endpoint.metadata.url; + } + + get name() { + return this.#nav_text.toString(); + } + + set name(name) { + this.#nav_text.text = name; + } + + get endpoint() { + return this.#nav_text.endpoint; + } + + get id() { + // XXX: maybe confirm that pageType == "WEB_PAGE_TYPE_CHANNEL"? + // TODO: this is outdated + return this.#nav_text.endpoint.browseId; + } + + /** + * @type {boolean} + */ + get is_verified() { + return this.badges.some(badge => badge.style === 'BADGE_STYLE_TYPE_VERIFIED'); + } + + /** + * @type {boolean} + */ + get is_verified_artist() { + return this.badges.some(badge => badge.style === 'BADGE_STYLE_TYPE_VERIFIED_ARTIST'); + } + + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail() { + return this.thumbnails[0]; } } diff --git a/lib/parser/contents/classes/BackstageImage.js b/lib/parser/contents/classes/BackstageImage.js new file mode 100644 index 000000000..bfff689bd --- /dev/null +++ b/lib/parser/contents/classes/BackstageImage.js @@ -0,0 +1,11 @@ +const Thumbnail = require('./Thumbnail'); + +class BackstageImage { + type = 'BackstageImage'; + + constructor(data) { + this.image = Thumbnail.fromResponse(data.image); + } +} + +module.exports = BackstageImage; \ No newline at end of file diff --git a/lib/parser/contents/classes/BackstagePost.js b/lib/parser/contents/classes/BackstagePost.js new file mode 100644 index 000000000..3ed928202 --- /dev/null +++ b/lib/parser/contents/classes/BackstagePost.js @@ -0,0 +1,26 @@ +const Parser = require('..'); +const Author = require('./Author'); +const Text = require('./Text'); + +class BackstagePost { + type = 'BackstagePost'; + + constructor(data) { + this.id = data.postId; + this.author = new Author({ + ...data.authorText, + navigationEndpoint: data.authorEndpoint + }, null, data.authorThumbnail); + this.content = new Text(data.contentText, ''); + this.published_at = new Text(data.publishedTimeText); + this.likes = new Text(data.voteCount); + this.actions = Parser.parse(data.actionButtons); + this.attachment = data.backstageAttachment ? Parser.parse(data.backstageAttachment) : null; + } + + get endpoint() { + return this.actions.reply.endpoint; + } +} + +module.exports = BackstagePost; \ No newline at end of file diff --git a/lib/parser/contents/classes/BackstagePostThread.js b/lib/parser/contents/classes/BackstagePostThread.js new file mode 100644 index 000000000..e0eebd530 --- /dev/null +++ b/lib/parser/contents/classes/BackstagePostThread.js @@ -0,0 +1,11 @@ +const Parser = require('..'); + +class BackstagePostThread { + type = 'BackstagePostThread'; + + constructor(data) { + this.post = Parser.parse(data.post); + } +} + +module.exports = BackstagePostThread; \ No newline at end of file diff --git a/lib/parser/contents/classes/Button.js b/lib/parser/contents/classes/Button.js index 914b23f79..56bfdd228 100644 --- a/lib/parser/contents/classes/Button.js +++ b/lib/parser/contents/classes/Button.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class Button { - type = 'buttonRenderer'; + type = 'Button'; constructor(data) { this.text = new Text(data.text).toString(); diff --git a/lib/parser/contents/classes/C4TabbedHeader.js b/lib/parser/contents/classes/C4TabbedHeader.js new file mode 100644 index 000000000..f9f3bc5fa --- /dev/null +++ b/lib/parser/contents/classes/C4TabbedHeader.js @@ -0,0 +1,24 @@ +const Parser = require('..'); +const Author = require('./Author'); +const Thumbnail = require('./Thumbnail'); +const Text = require('./Text'); + +class C4TabbedHeader { + type = 'C4TabbedHeader'; + + constructor(data) { + this.author = new Author({ + simpleText: data.title, + navigationEndpoint: data.navigationEndpoint + }, data.badges, data.avatar); + this.banner = data.banner && Thumbnail.fromResponse(data.banner) || []; + this.tv_banner = data.tvBanner && Thumbnail.fromResponse(data.tvBanner) || []; + this.mobile_banner = data.mobileBanner && Thumbnail.fromResponse(data.mobileBanner) || []; + this.subscribers = new Text(data.subscriberCountText); + this.sponsor_button = data.sponsorButton && Parser.parse(data.sponsorButton); + this.subscribe_button = data.subscribeButton && Parser.parse(data.subscribeButton); + this.header_links = data.headerLinks && Parser.parse(data.headerLinks); + } +} + +module.exports = C4TabbedHeader; diff --git a/lib/parser/contents/classes/Card.js b/lib/parser/contents/classes/Card.js index f84b13c3b..cb69c5620 100644 --- a/lib/parser/contents/classes/Card.js +++ b/lib/parser/contents/classes/Card.js @@ -3,7 +3,7 @@ const Parser = require('..'); class Card { - type = 'cardRenderer'; + type = 'Card'; constructor(data) { this.teaser = Parser.parse(data.teaser); diff --git a/lib/parser/contents/classes/CardCollection.js b/lib/parser/contents/classes/CardCollection.js index f5f4311eb..11c7aec53 100644 --- a/lib/parser/contents/classes/CardCollection.js +++ b/lib/parser/contents/classes/CardCollection.js @@ -4,7 +4,7 @@ const Parser = require('..'); const Text = require('./Text'); class CardCollection { - type = 'cardCollectionRenderer'; + type = 'CardCollection'; constructor(data) { this.cards = Parser.parse(data.cards); diff --git a/lib/parser/contents/classes/Channel.js b/lib/parser/contents/classes/Channel.js new file mode 100644 index 000000000..bd90ac7f3 --- /dev/null +++ b/lib/parser/contents/classes/Channel.js @@ -0,0 +1,21 @@ +const Author = require('./Author'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class Channel { + type = 'Channel'; + + constructor(data) { + this.id = data.channelId; + this.author = new Author({ + ...data.title, + navigationEndpoint: data.navigationEndpoint + }, data.ownerBadges, data.thumbnail); + this.subscribers = new Text(data.subscriberCountText); + this.videos = new Text(data.videoCountText); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + this.description_snippet = new Text(data.descriptionSnippet); + } +} + +module.exports = Channel; \ No newline at end of file diff --git a/lib/parser/contents/classes/ChannelAboutFullMetadata.js b/lib/parser/contents/classes/ChannelAboutFullMetadata.js new file mode 100644 index 000000000..6537a65c7 --- /dev/null +++ b/lib/parser/contents/classes/ChannelAboutFullMetadata.js @@ -0,0 +1,21 @@ +const Author = require('./Author'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class ChannelAboutFullMetadata { + type = 'ChannelAboutFullMetadata'; + + constructor(data) { + this.id = data.channelId; + this.canonical_channel_url = data.canonicalChannelUrl; + this.author = new Author(data.title, null, data.avatar); + this.views = new Text(data.viewCountText); + this.joined = new Text(data.joinedDateText); + this.description = new Text(data.description); + this.email_reveal = new NavigationEndpoint(data.onBusinessEmailRevealClickCommand); + this.can_reveal_email = !data.signInForBusinessEmail; + this.country = new Text(data.country); + } +} + +module.exports = ChannelAboutFullMetadata; \ No newline at end of file diff --git a/lib/parser/contents/classes/ChannelHeaderLinks.js b/lib/parser/contents/classes/ChannelHeaderLinks.js new file mode 100644 index 000000000..76e857bb4 --- /dev/null +++ b/lib/parser/contents/classes/ChannelHeaderLinks.js @@ -0,0 +1,22 @@ +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); +const Thumbnail = require('./Thumbnail'); + +class HeaderLink { + constructor(data) { + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + this.icon = Thumbnail.fromResponse(data.icon); + this.title = new Text(data.title); + } +} + +class ChannelHeaderLinks { + type = 'ChannelHeaderLinks'; + + constructor(data) { + this.primary = data.primaryLinks.map(link => new HeaderLink(link)); + this.secondary = data.secondaryLinks.map(link => new HeaderLink(link)); + } +} + +module.exports = ChannelHeaderLinks; \ No newline at end of file diff --git a/lib/parser/contents/classes/ChannelMetadata.js b/lib/parser/contents/classes/ChannelMetadata.js new file mode 100644 index 000000000..40d4d6339 --- /dev/null +++ b/lib/parser/contents/classes/ChannelMetadata.js @@ -0,0 +1,23 @@ +const Thumbnail = require('./Thumbnail'); + +class ChannelMetadata { + type = 'ChannelMetadata'; + + constructor(data) { + this.title = data.title; + this.description = data.description; + this.url = data.channelUrl; + this.rss_urls = data.rssUrl; + this.vanity_channel_url = data.vanityChannelUrl; + this.external_id = data.externalId; + this.is_family_safe = data.isFamilySafe; + this.keywords = data.keywords; + this.avatar = Thumbnail.fromResponse(data.avatar); + this.available_countries = data.availableCountryCodes; + this.android_deep_link = data.androidDeepLink; + this.android_appindexing_link = data.androidAppindexingLink; + this.ios_appindexing_link = data.iosAppindexingLink; + } +} + +module.exports = ChannelMetadata; \ No newline at end of file diff --git a/lib/parser/contents/classes/ChannelThumbnailWithLink.js b/lib/parser/contents/classes/ChannelThumbnailWithLink.js index 0b662c0e6..784bcee3b 100644 --- a/lib/parser/contents/classes/ChannelThumbnailWithLink.js +++ b/lib/parser/contents/classes/ChannelThumbnailWithLink.js @@ -4,10 +4,10 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class ChannelThumbnailWithLink { - type = 'channelThumbnailWithLinkRenderer'; + type = 'ChannelThumbnailWithLink'; constructor(data) { - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.label = data.accessibility.accessibilityData.label; } diff --git a/lib/parser/contents/classes/ChannelVideoPlayer.js b/lib/parser/contents/classes/ChannelVideoPlayer.js new file mode 100644 index 000000000..800e36399 --- /dev/null +++ b/lib/parser/contents/classes/ChannelVideoPlayer.js @@ -0,0 +1,15 @@ +const Text = require('./Text'); + +class ChannelVideoPlayer { + type = 'ChannelVideoPlayer'; + + constructor(data) { + this.id = data.videoId; + this.title = new Text(data.title, ''); + this.description = new Text(data.description, ''); + this.views = new Text(data.viewCountText, ''); + this.published_at = new Text(data.publishedTimeText, ''); + } +} + +module.exports = ChannelVideoPlayer; \ No newline at end of file diff --git a/lib/parser/contents/classes/ChildVideo.js b/lib/parser/contents/classes/ChildVideo.js index d8de7ce3c..738548382 100644 --- a/lib/parser/contents/classes/ChildVideo.js +++ b/lib/parser/contents/classes/ChildVideo.js @@ -5,7 +5,7 @@ const Utils = require('../../../utils/Utils'); const Text = require('./Text'); class ChildVideo { - type = 'childVideoRenderer'; + type = 'ChildVideo'; constructor(data) { this.id = data.videoId; diff --git a/lib/parser/contents/classes/ChipCloud.js b/lib/parser/contents/classes/ChipCloud.js index b83d8ded0..6a766ef44 100644 --- a/lib/parser/contents/classes/ChipCloud.js +++ b/lib/parser/contents/classes/ChipCloud.js @@ -3,7 +3,7 @@ const Parser = require('..'); class ChipCloud { - type = 'chipCloudRenderer'; + type = 'ChipCloud'; constructor(data) { this.chips = Parser.parse(data.chips); diff --git a/lib/parser/contents/classes/ChipCloudChip.js b/lib/parser/contents/classes/ChipCloudChip.js index 4c75d2983..fea2ae2bf 100644 --- a/lib/parser/contents/classes/ChipCloudChip.js +++ b/lib/parser/contents/classes/ChipCloudChip.js @@ -1,15 +1,14 @@ -'use strict'; - -const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); class ChipCloudChip { - type = 'chipCloudChipRenderer'; - + type = 'ChipCloudChip'; + constructor(data) { - this.text = new Text(data.text).toString(); - this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + // TODO: is this isSelected or just selected this.is_selected = data.isSelected; + this.endpoint = data.navigationEndpoint && new NavigationEndpoint(data.navigationEndpoint); + this.text = new Text(data.text); } } diff --git a/lib/parser/contents/classes/CollageHeroImage.js b/lib/parser/contents/classes/CollageHeroImage.js new file mode 100644 index 000000000..c76ca2c30 --- /dev/null +++ b/lib/parser/contents/classes/CollageHeroImage.js @@ -0,0 +1,15 @@ +const NavigationEndpoint = require('./NavigationEndpoint'); +const Thumbnail = require('./Thumbnail'); + +class CollageHeroImage { + type = 'CollageHeroImage'; + + constructor(data) { + this.left = Thumbnail.fromResponse(data.leftThumbnail); + this.top_right = Thumbnail.fromResponse(data.topRightThumbnail); + this.bottom_right = Thumbnail.fromResponse(data.bottomRightThumbnail); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + } +} + +module.exports = CollageHeroImage; \ No newline at end of file diff --git a/lib/parser/contents/classes/CommentActionButtons.js b/lib/parser/contents/classes/CommentActionButtons.js new file mode 100644 index 000000000..ca8bb32dd --- /dev/null +++ b/lib/parser/contents/classes/CommentActionButtons.js @@ -0,0 +1,13 @@ +const Parser = require('..'); + +class CommentActionButtons { + type = 'CommentActionButtons'; + + constructor(data) { + this.like = Parser.parse(data.likeButton); + this.reply = Parser.parse(data.replyButton); + this.dislike = Parser.parse(data.dislikeButton); + } +} + +module.exports = CommentActionButtons; \ No newline at end of file diff --git a/lib/parser/contents/classes/CommentsEntryPointHeader.js b/lib/parser/contents/classes/CommentsEntryPointHeader.js index 26d48e258..afefcca8c 100644 --- a/lib/parser/contents/classes/CommentsEntryPointHeader.js +++ b/lib/parser/contents/classes/CommentsEntryPointHeader.js @@ -4,12 +4,12 @@ const Text = require('./Text'); const Thumbnail = require('./Thumbnail'); class CommentsEntryPointHeader { - type = 'commentsEntryPointHeaderRenderer'; + type = 'CommentsEntryPointHeader'; constructor(data) { this.header = new Text(data.headerText); this.comment_count = new Text(data.commentCount); - this.teaser_avatar = new Thumbnail(data.teaserAvatar || data.simpleboxAvatar).thumbnails; + this.teaser_avatar = Thumbnail.fromResponse(data.teaserAvatar || data.simpleboxAvatar); this.teaser_content = new Text(data.teaserContent); this.simplebox_placeholder = new Text(data.simpleboxPlaceholder); } diff --git a/lib/parser/contents/classes/CompactMix.js b/lib/parser/contents/classes/CompactMix.js index 840785dc8..cc02150ed 100644 --- a/lib/parser/contents/classes/CompactMix.js +++ b/lib/parser/contents/classes/CompactMix.js @@ -3,7 +3,7 @@ const Playlist = require('./Playlist'); class CompactMix extends Playlist { - type = 'compactMixRenderer'; + type = 'CompactMix'; constructor(data) { super(data); diff --git a/lib/parser/contents/classes/CompactVideo.js b/lib/parser/contents/classes/CompactVideo.js index 0a9add415..04596915f 100644 --- a/lib/parser/contents/classes/CompactVideo.js +++ b/lib/parser/contents/classes/CompactVideo.js @@ -8,12 +8,15 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class CompactVideo { - type = 'compactVideoRenderer'; + type = 'CompactVideo'; constructor(data) { this.id = data.videoId; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); + this.rich_thumbnail = data.richThumbnail && Parser.parse(data.richThumbnail); this.title = new Text(data.title); - this.author = new Author({ nav_text: data.longBylineText, badges: data.ownerBadges || data.badges }); + this.author = new Author(data.longBylineText, data.ownerBadges, data.channelThumbnail); + this.view_count = new Text(data.viewCountText); this.short_view_count = new Text(data.shortViewCountText); this.published = new Text(data.publishedTimeText); @@ -23,12 +26,14 @@ class CompactVideo { seconds: Utils.timeToSeconds(new Text(data.lengthText).toString()) }; - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; - this.channel_thumbnails = new Thumbnail(data.channelThumbnail).thumbnails; this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.menu = Parser.parse(data.menu); } + + get best_thumbnail() { + return this.thumbnails[0]; + } } module.exports = CompactVideo; \ No newline at end of file diff --git a/lib/parser/contents/classes/ContinuationItem.js b/lib/parser/contents/classes/ContinuationItem.js index 38726e0e4..9c7222de2 100644 --- a/lib/parser/contents/classes/ContinuationItem.js +++ b/lib/parser/contents/classes/ContinuationItem.js @@ -3,7 +3,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class ContinuationItem { - type = 'continuationItemRenderer'; + type = 'ContinuationItem'; constructor(data) { this.trigger = data.trigger; diff --git a/lib/parser/contents/classes/CtaGoToCreatorStudio.js b/lib/parser/contents/classes/CtaGoToCreatorStudio.js index 51b45db42..52b3690c6 100644 --- a/lib/parser/contents/classes/CtaGoToCreatorStudio.js +++ b/lib/parser/contents/classes/CtaGoToCreatorStudio.js @@ -1,7 +1,7 @@ 'use strict'; class CtaGoToCreatorStudio { - type = 'ctaGoToCreatorStudioModel'; + type = 'CtaGoToCreatorStudio'; constructor(data) { this.title = data.buttonLabel; diff --git a/lib/parser/contents/classes/DataModelSection.js b/lib/parser/contents/classes/DataModelSection.js index 105dc9869..ae6463a7c 100644 --- a/lib/parser/contents/classes/DataModelSection.js +++ b/lib/parser/contents/classes/DataModelSection.js @@ -1,7 +1,7 @@ 'use strict'; class DataModelSection { - type = 'dataModelSection'; + type = 'DataModelSection'; constructor(data) { this.title = data.title; diff --git a/lib/parser/contents/classes/DidYouMean.js b/lib/parser/contents/classes/DidYouMean.js index 379238b8e..b731cac61 100644 --- a/lib/parser/contents/classes/DidYouMean.js +++ b/lib/parser/contents/classes/DidYouMean.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class DidYouMean { - type = 'didYouMeanRenderer'; + type = 'DidYouMean'; constructor(data) { this.corrected_query = new Text(data.correctedQuery); diff --git a/lib/parser/contents/classes/DownloadButton.js b/lib/parser/contents/classes/DownloadButton.js index 2007d7c49..81ffc73f4 100644 --- a/lib/parser/contents/classes/DownloadButton.js +++ b/lib/parser/contents/classes/DownloadButton.js @@ -3,7 +3,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class DownloadButton { - type = 'buttonRenderer'; + type = 'DownloadButton'; constructor(data) { this.style = data.style; diff --git a/lib/parser/contents/classes/Element.js b/lib/parser/contents/classes/Element.js index b1eda6f48..c1ddacbf4 100644 --- a/lib/parser/contents/classes/Element.js +++ b/lib/parser/contents/classes/Element.js @@ -3,7 +3,7 @@ const Parser = require('..'); class Element { - type = 'elementRenderer'; + type = 'Element'; constructor(data) { const type = data.newElement.type.componentType; diff --git a/lib/parser/contents/classes/EmergencyOnebox.js b/lib/parser/contents/classes/EmergencyOnebox.js index df4ab7d98..8f51d8e72 100644 --- a/lib/parser/contents/classes/EmergencyOnebox.js +++ b/lib/parser/contents/classes/EmergencyOnebox.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const Parser = require('..'); class EmergencyOnebox { - type = 'emergencyOneboxRenderer'; + type = 'EmergencyOnebox'; constructor(data) { this.title = new Text(data.title); diff --git a/lib/parser/contents/classes/EndScreenPlaylist.js b/lib/parser/contents/classes/EndScreenPlaylist.js index 9cf9bea8d..f93d2f20a 100644 --- a/lib/parser/contents/classes/EndScreenPlaylist.js +++ b/lib/parser/contents/classes/EndScreenPlaylist.js @@ -5,14 +5,14 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class EndScreenPlaylist { - type = 'endScreenPlaylistRenderer'; + type = 'EndScreenPlaylist'; constructor(data) { this.id = data.playlistId; this.title = new Text(data.title); this.author = new Text(data.longBylineText); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.video_count = new Text(data.videoCountText); } } diff --git a/lib/parser/contents/classes/EndScreenVideo.js b/lib/parser/contents/classes/EndScreenVideo.js index 14bce7fb8..33172031a 100644 --- a/lib/parser/contents/classes/EndScreenVideo.js +++ b/lib/parser/contents/classes/EndScreenVideo.js @@ -7,12 +7,12 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class EndScreenVideo { - type = 'endScreenVideoRenderer'; + type = 'EndScreenVideo'; constructor(data) { this.id = data.videoId; this.title = new Text(data.title); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays); this.author = new Author({ nav_text: data.shortBylineText, badges: data.ownerBadges || data.badges }); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); diff --git a/lib/parser/contents/classes/Endscreen.js b/lib/parser/contents/classes/Endscreen.js index b553533b6..b30662de8 100644 --- a/lib/parser/contents/classes/Endscreen.js +++ b/lib/parser/contents/classes/Endscreen.js @@ -3,7 +3,7 @@ const Parser = require('..'); class Endscreen { - type = 'endscreenRenderer'; + type = 'Endscreen'; constructor(data) { this.elements = Parser.parse(data.elements); diff --git a/lib/parser/contents/classes/EndscreenElement.js b/lib/parser/contents/classes/EndscreenElement.js index 2bd257300..ef26fb7e2 100644 --- a/lib/parser/contents/classes/EndscreenElement.js +++ b/lib/parser/contents/classes/EndscreenElement.js @@ -6,16 +6,16 @@ const NavigationEndpoint = require('./NavigationEndpoint'); const Text = require('./Text'); class EndscreenElement { - type = 'endscreenRenderer'; + type = 'EndscreenElement'; constructor(data) { this.style = data.style; data.image && - (this.image = new Thumbnail(data.image).thumbnails); + (this.image = Thumbnail.fromResponse(data.image)); data.icon && - (this.icon = new Thumbnail(data.icon).thumbnails); + (this.icon = Thumbnail.fromResponse(data.icon)); data.metadata && (this.metadata = new Text(data.metadata)); diff --git a/lib/parser/contents/classes/ExpandableTab.js b/lib/parser/contents/classes/ExpandableTab.js new file mode 100644 index 000000000..35dc62aba --- /dev/null +++ b/lib/parser/contents/classes/ExpandableTab.js @@ -0,0 +1,15 @@ +const Parser = require('..'); +const NavigationEndpoint = require('./NavigationEndpoint'); + +class ExpandableTab { + type = 'ExpandableTab'; + + constructor(data) { + this.title = data.title; + this.endpoint = new NavigationEndpoint(data.endpoint); + this.selected = data.selected; // if this.selected then we may have content else we do not + this.content = data.content ? Parser.parse(data.content) : null; + } +} + +module.exports = ExpandableTab; \ No newline at end of file diff --git a/lib/parser/contents/classes/ExpandedShelfContents.js b/lib/parser/contents/classes/ExpandedShelfContents.js new file mode 100644 index 000000000..f24f12c59 --- /dev/null +++ b/lib/parser/contents/classes/ExpandedShelfContents.js @@ -0,0 +1,14 @@ +'use strict'; + +const Parser = require('..'); + +class ExpandedShelfContents { + type = 'ExpandedShelfContents'; + + constructor(data) { + this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency + } +} + +module.exports = ExpandedShelfContents; \ No newline at end of file diff --git a/lib/parser/contents/classes/FeedFilterChipBar.js b/lib/parser/contents/classes/FeedFilterChipBar.js new file mode 100644 index 000000000..8581d5541 --- /dev/null +++ b/lib/parser/contents/classes/FeedFilterChipBar.js @@ -0,0 +1,11 @@ +const Parser = require('..'); + +class FeedFilterChipBar { + type = 'FeedFilterChipBar'; + + constructor(data) { + this.contents = Parser.parse(data.contents); + } +} + +module.exports = FeedFilterChipBar; \ No newline at end of file diff --git a/lib/parser/contents/classes/Format.js b/lib/parser/contents/classes/Format.js index bae47fba9..1453dd5df 100644 --- a/lib/parser/contents/classes/Format.js +++ b/lib/parser/contents/classes/Format.js @@ -12,10 +12,16 @@ class Format { this.average_bitrate = data.averageBitrate; this.width = data.width || null; this.height = data.height || null; - this.init_range = data.initRange; - this.index_range = data.indexRange; - this.last_modified = data.lastModified; - this.content_length = data.contentLength; + this.init_range = data.initRange && { + start: parseInt(data.initRange.start), + end: parseInt(data.initRange.end) + }; + this.index_range = data.indexRange && { + start: parseInt(data.indexRange.start), + end: parseInt(data.indexRange.end) + }; + this.last_modified = new Date(Math.floor(parseInt(data.lastModified) / 1000)); + this.content_length = parseInt(data.contentLength); this.quality = data.quality; this.quality_label = data.qualityLabel || null; this.fps = data.fps || null; @@ -23,7 +29,8 @@ class Format { this.cipher = data.cipher || null; this.signature_cipher = data.signatureCipher || null; this.audio_quality = data.audioQuality; - this.approx_duration_ms = data.approxDurationMs; + this.approx_duration_ms = parseInt(data.approxDurationMs); + this.audio_sample_rate = parseInt(data.audioSampleRate); this.audio_channels = data.audioChannels; this.loudness_db = data.loudnessDb; this.has_audio = !!data.audioBitrate || !!data.audioQuality; diff --git a/lib/parser/contents/classes/Grid.js b/lib/parser/contents/classes/Grid.js index d0dd3bc2c..2426501bc 100644 --- a/lib/parser/contents/classes/Grid.js +++ b/lib/parser/contents/classes/Grid.js @@ -3,10 +3,11 @@ const Parser = require('..'); class Grid { - type = 'gridRenderer'; + type = 'Grid'; constructor(data) { this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency this.is_collapsible = data.isCollapsible; this.visible_row_count = data.visibleRowCount; this.target_id = data.targetId; diff --git a/lib/parser/contents/classes/GridChannel.js b/lib/parser/contents/classes/GridChannel.js new file mode 100644 index 000000000..337324820 --- /dev/null +++ b/lib/parser/contents/classes/GridChannel.js @@ -0,0 +1,20 @@ +const Author = require('./Author'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class GridChannel { + type = 'GridChannel'; + + constructor(data) { + this.id = data.channelId; + this.author = new Author({ + ...data.title, + navigationEndpoint: data.navigationEndpoint + }, data.ownerBadges, data.thumbnail); + this.subscribers = new Text(data.subscriberCountText); + this.videos = new Text(data.videoCountText); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + } +} + +module.exports = GridChannel; \ No newline at end of file diff --git a/lib/parser/contents/classes/GridPlaylist.js b/lib/parser/contents/classes/GridPlaylist.js index 4cdc58ea7..351dcd7a6 100644 --- a/lib/parser/contents/classes/GridPlaylist.js +++ b/lib/parser/contents/classes/GridPlaylist.js @@ -5,9 +5,10 @@ const Parser = require('..'); const Thumbnail = require('./Thumbnail'); const PlaylistAuthor = require('./PlaylistAuthor'); const NavigationEndpoint = require('./NavigationEndpoint'); +const NavigatableText = require('./NavigatableText'); class GridPlaylist { - type = 'gridPlaylistRenderer'; + type = 'GridPlaylist'; constructor(data) { this.id = data.playlistId; @@ -15,8 +16,9 @@ class GridPlaylist { this.author = new PlaylistAuthor({ nav_text: data.shortBylineText }); this.badges = Parser.parse(data.ownerBadges); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; - this.sidebar_thumbnails = [].concat(...data.sidebarThumbnails?.map((thumbnail) => new Thumbnail(thumbnail).thumbnails) || []) || null; + this.view_playlist = new NavigatableText(data.viewPlaylistText); + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); + this.sidebar_thumbnails = [].concat(...data.sidebarThumbnails?.map((thumbnail) => Thumbnail.fromResponse(thumbnail)) || []) || null; this.video_count = new Text(data.thumbnailText); this.video_count_short_text = new Text(data.videoCountShortText); } diff --git a/lib/parser/contents/classes/GridVideo.js b/lib/parser/contents/classes/GridVideo.js index 7fa830ee4..e93643e63 100644 --- a/lib/parser/contents/classes/GridVideo.js +++ b/lib/parser/contents/classes/GridVideo.js @@ -7,18 +7,19 @@ const NavigationEndpoint = require('./NavigationEndpoint'); const Author = require('./Author'); class GridVideo { - type = 'gridVideoRenderer'; + type = 'GridVideo'; constructor(data) { const length_alt = data.thumbnailOverlays.find(overlay => overlay.hasOwnProperty('thumbnailOverlayTimeStatusRenderer'))?.thumbnailOverlayTimeStatusRenderer; this.id = data.videoId; this.title = new Text(data.title); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays); + this.rich_thumbnail = data.richThumbnail && Parser.parse(data.richThumbnail); this.published = new Text(data.publishedTimeText); this.duration = data.lengthText ? new Text(data.lengthText) : length_alt?.text ? new Text(length_alt.text) : ''; - this.author = new Author({ nav_text: data.shortBylineText, badges: data.ownerBadges }); + this.author = data.shortBylineText && new Author(data.shortBylineText, data.ownerBadges); this.views = new Text(data.viewCountText); this.short_view_count = new Text(data.shortViewCountText); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); diff --git a/lib/parser/contents/classes/HorizontalCardList.js b/lib/parser/contents/classes/HorizontalCardList.js index f20fac308..9ba90b6b4 100644 --- a/lib/parser/contents/classes/HorizontalCardList.js +++ b/lib/parser/contents/classes/HorizontalCardList.js @@ -3,7 +3,7 @@ const Parser = require('..'); class HorizontalCardList { - type = 'horizontalCardListRenderer'; + type = 'HorizontalCardList'; constructor(data) { this.cards = Parser.parse(data.cards); diff --git a/lib/parser/contents/classes/HorizontalList.js b/lib/parser/contents/classes/HorizontalList.js new file mode 100644 index 000000000..607427ca9 --- /dev/null +++ b/lib/parser/contents/classes/HorizontalList.js @@ -0,0 +1,13 @@ +const Parser = require('..'); + +class HorizontalList { + type = 'HorizontalList'; + + constructor(data) { + this.visible_item_count = data.visibleItemCount; + this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency + } +} + +module.exports = HorizontalList; \ No newline at end of file diff --git a/lib/parser/contents/classes/ItemSection.js b/lib/parser/contents/classes/ItemSection.js index cfb096e28..f00ee1e8a 100644 --- a/lib/parser/contents/classes/ItemSection.js +++ b/lib/parser/contents/classes/ItemSection.js @@ -3,7 +3,7 @@ const Parser = require('..'); class ItemSection { - type = 'itemSectionRenderer'; + type = 'ItemSection'; constructor(data) { this.header = Parser.parse(data.header); diff --git a/lib/parser/contents/classes/LikeButton.js b/lib/parser/contents/classes/LikeButton.js index 13a7fe0d8..fec104bf8 100644 --- a/lib/parser/contents/classes/LikeButton.js +++ b/lib/parser/contents/classes/LikeButton.js @@ -3,7 +3,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class LikeButton { - type = 'likeButtonRenderer'; + type = 'LikeButton'; constructor(data) { this.target = { diff --git a/lib/parser/contents/classes/Menu.js b/lib/parser/contents/classes/Menu.js index 6af849a38..b8b8b7f61 100644 --- a/lib/parser/contents/classes/Menu.js +++ b/lib/parser/contents/classes/Menu.js @@ -3,10 +3,11 @@ const Parser = require('..'); class Menu { - type = 'menuRenderer'; + type = 'Menu'; constructor(data) { this.items = Parser.parse(data.items) || []; + this.contents = this.items; // XXX: alias for consistency this.top_level_buttons = Parser.parse(data.topLevelButtons) || []; this.label = data.accessibility?.accessibilityData?.label || null; } diff --git a/lib/parser/contents/classes/MenuNavigationItem.js b/lib/parser/contents/classes/MenuNavigationItem.js index 2433a3e08..0be59e888 100644 --- a/lib/parser/contents/classes/MenuNavigationItem.js +++ b/lib/parser/contents/classes/MenuNavigationItem.js @@ -3,7 +3,7 @@ const Button = require('./Button'); class MenuNavigationItem extends Button { - type = 'menuNavigationItemRenderer'; + type = 'MenuNavigationItem'; constructor(data) { super(data); diff --git a/lib/parser/contents/classes/MenuServiceItem.js b/lib/parser/contents/classes/MenuServiceItem.js index fab1d8b0b..82069560f 100644 --- a/lib/parser/contents/classes/MenuServiceItem.js +++ b/lib/parser/contents/classes/MenuServiceItem.js @@ -3,7 +3,7 @@ const Button = require('./Button'); class MenuServiceItem extends Button { - type = 'menuServiceItemRenderer'; + type = 'MenuServiceItem'; constructor(data) { super(data); diff --git a/lib/parser/contents/classes/MenuServiceItemDownload.js b/lib/parser/contents/classes/MenuServiceItemDownload.js new file mode 100644 index 000000000..17d57f68a --- /dev/null +++ b/lib/parser/contents/classes/MenuServiceItemDownload.js @@ -0,0 +1,14 @@ +'use strict'; + +const NavigationEndpoint = require('./NavigationEndpoint'); + +class MenuServiceItemDownload { + type = 'MenuServiceItemDownload'; + + constructor(data) { + this.has_separator = data.hasSeparator; + this.endpoint = new NavigationEndpoint(data.navigationEndpoint || data.serviceEndpoint); + } +} + +module.exports = MenuServiceItemDownload; \ No newline at end of file diff --git a/lib/parser/contents/classes/MerchandiseItem.js b/lib/parser/contents/classes/MerchandiseItem.js index da06c9e9d..836af2a64 100644 --- a/lib/parser/contents/classes/MerchandiseItem.js +++ b/lib/parser/contents/classes/MerchandiseItem.js @@ -4,12 +4,12 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class MerchandiseItem { - type = 'merchandiseItemRenderer'; + type = 'MerchandiseItem'; constructor(data) { this.title = data.title; this.description = data.description; - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.price = data.price; this.vendor_name = data.vendorName; this.button_text = data.buttonText; diff --git a/lib/parser/contents/classes/MerchandiseShelf.js b/lib/parser/contents/classes/MerchandiseShelf.js index 54b6e004c..f6447d5e2 100644 --- a/lib/parser/contents/classes/MerchandiseShelf.js +++ b/lib/parser/contents/classes/MerchandiseShelf.js @@ -3,12 +3,13 @@ const Parser = require('..'); class MerchandiseShelf { - type = 'merchandiseShelfRenderer'; + type = 'MerchandiseShelf'; constructor(data) { this.title = data.title; this.menu = Parser.parse(data.actionButton); this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency } } diff --git a/lib/parser/contents/classes/Message.js b/lib/parser/contents/classes/Message.js index 6929d1232..72f561262 100644 --- a/lib/parser/contents/classes/Message.js +++ b/lib/parser/contents/classes/Message.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class Message { - type = 'messageRenderer' + type = 'Message' constructor(data) { this.text = new Text(data.text).toString(); diff --git a/lib/parser/contents/classes/MetadataRow.js b/lib/parser/contents/classes/MetadataRow.js index 9f41abb9e..e8288bfdf 100644 --- a/lib/parser/contents/classes/MetadataRow.js +++ b/lib/parser/contents/classes/MetadataRow.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class MetadataRow { - type = 'metadataRowRenderer'; + type = 'MetadataRow'; constructor(data) { this.title = new Text(data.title); diff --git a/lib/parser/contents/classes/MetadataRowContainer.js b/lib/parser/contents/classes/MetadataRowContainer.js index 396c41826..15b653fc9 100644 --- a/lib/parser/contents/classes/MetadataRowContainer.js +++ b/lib/parser/contents/classes/MetadataRowContainer.js @@ -3,7 +3,7 @@ const Parser = require('..'); class MetadataRowContainer { - type = 'metadataRowContainerRenderer'; + type = 'MetadataRowContainer'; constructor(data) { this.rows = Parser.parse(data.rows); diff --git a/lib/parser/contents/classes/MetadataRowHeader.js b/lib/parser/contents/classes/MetadataRowHeader.js index 6d0ed1daa..3fc344c5f 100644 --- a/lib/parser/contents/classes/MetadataRowHeader.js +++ b/lib/parser/contents/classes/MetadataRowHeader.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class MetadataRowHeader { - type = 'metadataRowHeaderRenderer'; + type = 'MetadataRowHeader'; constructor(data) { this.content = new Text(data.content); diff --git a/lib/parser/contents/classes/MicroformatData.js b/lib/parser/contents/classes/MicroformatData.js new file mode 100644 index 000000000..1ef6468f3 --- /dev/null +++ b/lib/parser/contents/classes/MicroformatData.js @@ -0,0 +1,34 @@ +const Thumbnail = require('./Thumbnail'); + +class MicroformatData { + type = 'MicroformatData'; + + constructor(data) { + this.url_canonical = data.urlCanonical; + this.title = data.title; + this.description = data.description; + this.thumbnail = data.thumbnail && Thumbnail.fromResponse(data.thumbnail); + this.site_name = data.siteName; + this.app_name = data.appName; + this.android_package = data.androidPackage; + this.ios_app_store_id = data.iosAppStoreId; + this.ios_app_arguments = data.iosAppArguments; + this.og_type = data.ogType; + this.url_applinks_web = data.urlApplinksWeb; + this.url_applinks_ios = data.urlApplinksIos; + this.url_applinks_android = data.urlApplinksAndroid; + this.url_twitter_ios = data.urlTwitterIos; + this.url_twitter_android = data.urlTwitterAndroid; + this.twitter_card_type = data.twitterCardType; + this.twitter_site_handle = data.twitterSiteHandle; + this.schema_dot_org_type = data.schemaDotOrgType; + this.noindex = data.noindex; + this.is_unlisted = data.unlisted; + this.is_family_safe = data.familySafe; + this.tags = data.tags; + this.available_countries = data.availableCountries; + // XXX: linkAlternatives? + } +} + +module.exports = MicroformatData; \ No newline at end of file diff --git a/lib/parser/contents/classes/Mix.js b/lib/parser/contents/classes/Mix.js index 21950f5b1..0f396615b 100644 --- a/lib/parser/contents/classes/Mix.js +++ b/lib/parser/contents/classes/Mix.js @@ -3,7 +3,7 @@ const Playlist = require('./Playlist'); class Mix extends Playlist { - type = 'radioRenderer'; + type = 'Mix'; constructor(data) { super(data); diff --git a/lib/parser/contents/classes/MovingThumbnail.js b/lib/parser/contents/classes/MovingThumbnail.js index b3c08c1da..bf48a86ec 100644 --- a/lib/parser/contents/classes/MovingThumbnail.js +++ b/lib/parser/contents/classes/MovingThumbnail.js @@ -3,7 +3,7 @@ const Thumbnail = require('./Thumbnail'); class MovingThumbnail { - type = 'movingThumbnailRenderer'; + type = 'MovingThumbnail'; #data; diff --git a/lib/parser/contents/classes/MusicCarouselShelf.js b/lib/parser/contents/classes/MusicCarouselShelf.js index 72e794aa4..467340515 100644 --- a/lib/parser/contents/classes/MusicCarouselShelf.js +++ b/lib/parser/contents/classes/MusicCarouselShelf.js @@ -3,7 +3,7 @@ const Parser = require('..'); class MusicCarouselShelf { - type = 'musicCarouselShelfRenderer'; + type = 'MusicCarouselShelf'; constructor(data) { this.header = Parser.parse(data.header); diff --git a/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js b/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js index 0872eb96c..831055587 100644 --- a/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js +++ b/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const Thumbnail = require('./Thumbnail'); class MusicCarouselShelfBasicHeader { - type = 'musicCarouselShelfBasicHeaderRenderer'; + type = 'MusicCarouselShelfBasicHeader'; constructor(data) { data.strapline && @@ -16,7 +16,7 @@ class MusicCarouselShelfBasicHeader { // ^^ redundant? data.thumbnail && - (this.thumbnail = new Thumbnail(data.thumbnail.musicThumbnailRenderer.thumbnail).thumbnails); + (this.thumbnail = Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail)); } } diff --git a/lib/parser/contents/classes/MusicDescriptionShelf.js b/lib/parser/contents/classes/MusicDescriptionShelf.js index ff9752e43..79712fac2 100644 --- a/lib/parser/contents/classes/MusicDescriptionShelf.js +++ b/lib/parser/contents/classes/MusicDescriptionShelf.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class MusicDescriptionShelf { - type = 'musicDescriptionShelfRenderer'; + type = 'MusicDescriptionShelf'; constructor(data) { this.description = new Text(data.description); diff --git a/lib/parser/contents/classes/MusicHeader.js b/lib/parser/contents/classes/MusicHeader.js index eb14a865f..62d5a005a 100644 --- a/lib/parser/contents/classes/MusicHeader.js +++ b/lib/parser/contents/classes/MusicHeader.js @@ -3,7 +3,7 @@ const Parser = require('..'); class MusicHeader { - type = 'musicHeaderRenderer'; + type = 'MusicHeader'; constructor(data) { this.header = Parser.parse(data.header); diff --git a/lib/parser/contents/classes/MusicInlineBadge.js b/lib/parser/contents/classes/MusicInlineBadge.js index 2ec85f602..a51e12e7c 100644 --- a/lib/parser/contents/classes/MusicInlineBadge.js +++ b/lib/parser/contents/classes/MusicInlineBadge.js @@ -1,5 +1,5 @@ class MusicInlineBadge { - type = 'musicInlineBadgeRenderer'; + type = 'MusicInlineBadge'; constructor(data) { this.icon_type = data.icon.iconType; diff --git a/lib/parser/contents/classes/MusicItemThumbnailOverlay.js b/lib/parser/contents/classes/MusicItemThumbnailOverlay.js index e732237d3..80507798d 100644 --- a/lib/parser/contents/classes/MusicItemThumbnailOverlay.js +++ b/lib/parser/contents/classes/MusicItemThumbnailOverlay.js @@ -3,7 +3,7 @@ const Parser = require('..'); class MusicItemThumbnailOverlay { - type = 'musicItemThumbnailOverlayRenderer'; + type = 'MusicItemThumbnailOverlay'; constructor(data) { this.content = Parser.parse(data.content); diff --git a/lib/parser/contents/classes/MusicPlayButton.js b/lib/parser/contents/classes/MusicPlayButton.js index 0f0217740..c2a154891 100644 --- a/lib/parser/contents/classes/MusicPlayButton.js +++ b/lib/parser/contents/classes/MusicPlayButton.js @@ -3,7 +3,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class MusicPlayButton { - type = 'musicPlayButtonRenderer'; + type = 'MusicPlayButton'; constructor(data) { this.endpoint = new NavigationEndpoint(data.playNavigationEndpoint); diff --git a/lib/parser/contents/classes/MusicQueue.js b/lib/parser/contents/classes/MusicQueue.js index 722fe1ed5..62bf5196c 100644 --- a/lib/parser/contents/classes/MusicQueue.js +++ b/lib/parser/contents/classes/MusicQueue.js @@ -3,7 +3,7 @@ const Parser = require('..'); class MusicQueue { - type = 'musicQueueRenderer'; + type = 'MusicQueue'; constructor(data) { this.content = Parser.parse(data.content); diff --git a/lib/parser/contents/classes/MusicResponsiveListItem.js b/lib/parser/contents/classes/MusicResponsiveListItem.js index a878a985b..fdd06c5d5 100644 --- a/lib/parser/contents/classes/MusicResponsiveListItem.js +++ b/lib/parser/contents/classes/MusicResponsiveListItem.js @@ -36,7 +36,7 @@ class MusicResponsiveListItem { break; } - this.thumbnails = new Thumbnail(data.thumbnail.musicThumbnailRenderer.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail); this.badges = Parser.parse(data.badges) || []; this.menu = Parser.parse(data.menu); diff --git a/lib/parser/contents/classes/MusicShelf.js b/lib/parser/contents/classes/MusicShelf.js index 8e1ba04ff..fd7f1a3bd 100644 --- a/lib/parser/contents/classes/MusicShelf.js +++ b/lib/parser/contents/classes/MusicShelf.js @@ -5,7 +5,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class MusicShelf { - type = 'musicShelfRenderer'; + type = 'MusicShelf'; constructor(data) { this.title = new Text(data.title); diff --git a/lib/parser/contents/classes/MusicTwoRowItem.js b/lib/parser/contents/classes/MusicTwoRowItem.js index 3407c7ba3..3dfce868f 100644 --- a/lib/parser/contents/classes/MusicTwoRowItem.js +++ b/lib/parser/contents/classes/MusicTwoRowItem.js @@ -6,7 +6,7 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class MusicTwoRowItem { - type = 'musicTwoRowItemRenderer'; + type = 'MusicTwoRowItem'; constructor(data) { this.title = new Text(data.title); @@ -73,7 +73,7 @@ class MusicTwoRowItem { break; } - this.thumbnail = new Thumbnail(data.thumbnailRenderer.musicThumbnailRenderer.thumbnail).thumbnails; + this.thumbnail = Thumbnail.fromResponse(data.thumbnailRenderer.musicThumbnailRenderer.thumbnail); this.thumbnail_overlay = Parser.parse(data.thumbnailOverlay); this.menu = Parser.parse(data.menu); } diff --git a/lib/parser/contents/classes/NavigatableText.js b/lib/parser/contents/classes/NavigatableText.js new file mode 100644 index 000000000..c3ec6e687 --- /dev/null +++ b/lib/parser/contents/classes/NavigatableText.js @@ -0,0 +1,24 @@ +const Text = require('./Text'); +const NavigationEndpoint = require('./NavigationEndpoint'); + +class NavigatableText extends Text { + type = 'NavigatableText'; + endpoint; + constructor(node) { + super(node); + // TODO: is this needed? Text now supports this itself + this.endpoint = + node.runs?.[0]?.navigationEndpoint ? + new NavigationEndpoint(node.runs[0].navigationEndpoint) : + node.navigationEndpoint ? + new NavigationEndpoint(node.navigationEndpoint) : + node.titleNavigationEndpoint ? + new NavigationEndpoint(node.titleNavigationEndpoint) : null; + } + + toJSON() { + return this; + } +} + +module.exports = NavigatableText; diff --git a/lib/parser/contents/classes/NavigationEndpoint.js b/lib/parser/contents/classes/NavigationEndpoint.js index 766dfaf98..7548c5cdd 100644 --- a/lib/parser/contents/classes/NavigationEndpoint.js +++ b/lib/parser/contents/classes/NavigationEndpoint.js @@ -3,7 +3,7 @@ const Parser = require('..'); class NavigationEndpoint { - type = 'navigationEndpoint'; + type = 'NavigationEndpoint'; constructor(data) { data?.serviceEndpoint && @@ -116,9 +116,9 @@ class NavigationEndpoint { if (data?.playlistEditEndpoint) { this.playlist_edit = { playlist_id: data.playlistEditEndpoint.playlistId, - actions: data.playlistEditEndpoint.actions.map((item) => ({ - action: item.action, - removed_video_id: item.removedVideoId + actions: data.playlistEditEndpoint.actions.map(() => ({ + action: data.action, + removed_video_id: data.removedVideoId })) } } diff --git a/lib/parser/contents/classes/PlayerAnnotationsExpanded.js b/lib/parser/contents/classes/PlayerAnnotationsExpanded.js index f7a9810cf..4637ff437 100644 --- a/lib/parser/contents/classes/PlayerAnnotationsExpanded.js +++ b/lib/parser/contents/classes/PlayerAnnotationsExpanded.js @@ -5,13 +5,13 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class PlayerAnnotationsExpanded { - type = 'playerAnnotationsExpandedRenderer'; + type = 'PlayerAnnotationsExpanded'; constructor(data) { this.featured_channel = { start_time_ms: data.featuredChannel.startTimeMs, end_time_ms: data.featuredChannel.endTimeMs, - watermark: new Thumbnail(data.featuredChannel.watermark).thumbnails, + watermark: Thumbnail.fromResponse(data.featuredChannel.watermark), channel_name: data.featuredChannel.channelName, endpoint: new NavigationEndpoint(data.featuredChannel.navigationEndpoint), subscribe_button: Parser.parse(data.featuredChannel.subscribeButton) diff --git a/lib/parser/contents/classes/PlayerCaptionsTracklist.js b/lib/parser/contents/classes/PlayerCaptionsTracklist.js index e6c986d22..69805aa12 100644 --- a/lib/parser/contents/classes/PlayerCaptionsTracklist.js +++ b/lib/parser/contents/classes/PlayerCaptionsTracklist.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class PlayerCaptionsTracklist { - type = 'playerCaptionsTracklistRenderer' + type = 'PlayerCaptionsTracklist' constructor(data) { this.caption_tracks = data.captionTracks.map((ct) => ({ diff --git a/lib/parser/contents/classes/PlayerErrorMessage.js b/lib/parser/contents/classes/PlayerErrorMessage.js index 78cfe2665..aed4091e1 100644 --- a/lib/parser/contents/classes/PlayerErrorMessage.js +++ b/lib/parser/contents/classes/PlayerErrorMessage.js @@ -5,13 +5,13 @@ const Text = require('./Text'); const Thumbnail = require('./Thumbnail'); class PlayerErrorMessage { - type = 'playerErrorMessageRenderer'; + type = 'PlayerErrorMessage'; constructor(data) { this.subreason = new Text(data.subreason); this.reason = new Text(data.reason); this.proceed_button = Parser.parse(data.proceedButton); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.icon_type = data.icon.iconType; } } diff --git a/lib/parser/contents/classes/PlayerLiveStoryboardSpec.js b/lib/parser/contents/classes/PlayerLiveStoryboardSpec.js index 8164440c1..491e348dd 100644 --- a/lib/parser/contents/classes/PlayerLiveStoryboardSpec.js +++ b/lib/parser/contents/classes/PlayerLiveStoryboardSpec.js @@ -1,10 +1,10 @@ 'use strict'; class PlayerLiveStoryboardSpec { - type = 'playerLiveStoryboardSpecRenderer'; + type = 'PlayerLiveStoryboardSpec'; constructor() { - // A little bit different from PlayerLiveStoryboardSpec + // TODO: A little bit different from PlayerLiveStoryboardSpec // https://i.ytimg.com/sb/5qap5aO4i9A/storyboard_live_90_2x2_b2/M$M.jpg?rs=AOn4CLC9s6IeOsw_gKvEbsbU9y-e2FVRTw#159#90#2#2 } } diff --git a/lib/parser/contents/classes/PlayerMicroformat.js b/lib/parser/contents/classes/PlayerMicroformat.js index 00383406a..f076d0561 100644 --- a/lib/parser/contents/classes/PlayerMicroformat.js +++ b/lib/parser/contents/classes/PlayerMicroformat.js @@ -4,12 +4,12 @@ const Text = require('./Text'); const Thumbnail = require('./Thumbnail'); class PlayerMicroformat { - type = 'playerMicroformatRenderer'; + type = 'PlayerMicroformat'; constructor(data) { this.title = new Text(data.title); this.description = new Text(data.description); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.embed = { iframe_url: data.embed.iframeUrl, flash_url: data.embed.flashUrl, diff --git a/lib/parser/contents/classes/PlayerOverlay.js b/lib/parser/contents/classes/PlayerOverlay.js index e6455db7b..c7e1c5366 100644 --- a/lib/parser/contents/classes/PlayerOverlay.js +++ b/lib/parser/contents/classes/PlayerOverlay.js @@ -3,7 +3,7 @@ const Parser = require('..'); class PlayerOverlay { - type = 'playerOverlayRenderer'; + type = 'PlayerOverlay'; constructor(data) { this.end_screen = Parser.parse(data.endScreen); diff --git a/lib/parser/contents/classes/PlayerOverlayAutoplay.js b/lib/parser/contents/classes/PlayerOverlayAutoplay.js index 9b2d4eb03..4b7d874e8 100644 --- a/lib/parser/contents/classes/PlayerOverlayAutoplay.js +++ b/lib/parser/contents/classes/PlayerOverlayAutoplay.js @@ -6,7 +6,7 @@ const Author = require('./Author'); const Thumbnail = require('./Thumbnail'); class PlayerOverlayAutoplay { - type = 'playerOverlayAutoplayRenderer'; + type = 'PlayerOverlayAutoplay'; constructor(data) { this.title = new Text(data.title); @@ -16,7 +16,7 @@ class PlayerOverlayAutoplay { this.prefer_immediate_redirect = data.preferImmediateRedirect; this.count_down_secs_for_fullscreen = data.countDownSecsForFullscreen; this.published = new Text(data.publishedTimeText); - this.background = new Thumbnail(data.background).thumbnails; + this.background = Thumbnail.fromResponse(data.background); this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays); this.author = new Author({ nav_text: data.byline }); this.cancel_button = Parser.parse(data.cancelButton); diff --git a/lib/parser/contents/classes/PlayerStoryboardSpec.js b/lib/parser/contents/classes/PlayerStoryboardSpec.js index 319f5268b..49f7afc69 100644 --- a/lib/parser/contents/classes/PlayerStoryboardSpec.js +++ b/lib/parser/contents/classes/PlayerStoryboardSpec.js @@ -1,7 +1,7 @@ 'use strict'; class PlayerStoryboardSpec { - type = 'playerStoryboardSpecRenderer'; + type = 'PlayerStoryboardSpec'; constructor(data) { const parts = data.spec.split('|'); diff --git a/lib/parser/contents/classes/Playlist.js b/lib/parser/contents/classes/Playlist.js index e5fafff2b..061ccc89a 100644 --- a/lib/parser/contents/classes/Playlist.js +++ b/lib/parser/contents/classes/Playlist.js @@ -7,7 +7,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); const PlaylistAuthor = require('./PlaylistAuthor'); class Playlist { - type = 'playlistRenderer'; + type = 'Playlist'; constructor(data) { this.id = data.playlistId; @@ -17,7 +17,7 @@ class Playlist { new Text(data.shortBylineText) || new PlaylistAuthor({ nav_text: data.shortBylineText, badges: data.ownerBadges }); - this.thumbnails = new Thumbnail(data.thumbnail || { thumbnails: data.thumbnails.map((th) => th.thumbnails).flat(1) }).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail || { thumbnails: data.thumbnails.map((th) => th.thumbnails).flat(1) }); this.video_count = new Text(data.thumbnailText); this.video_count_short = new Text(data.videoCountShortText); this.first_videos = Parser.parse(data.videos) || []; diff --git a/lib/parser/contents/classes/PlaylistMetadata.js b/lib/parser/contents/classes/PlaylistMetadata.js new file mode 100644 index 000000000..f8ec39aeb --- /dev/null +++ b/lib/parser/contents/classes/PlaylistMetadata.js @@ -0,0 +1,11 @@ +class PlaylistMetadata { + type = 'PlaylistMetadata'; + + constructor(data) { + this.title = data.title; + this.description = data.description; + // XXX: Appindexing should be in microformat + } +} + +module.exports = PlaylistMetadata; \ No newline at end of file diff --git a/lib/parser/contents/classes/PlaylistPanel.js b/lib/parser/contents/classes/PlaylistPanel.js index 5d67d4a7c..2a9fc0b56 100644 --- a/lib/parser/contents/classes/PlaylistPanel.js +++ b/lib/parser/contents/classes/PlaylistPanel.js @@ -4,7 +4,7 @@ const Parser = require('..'); const Text = require('./Text'); class PlaylistPanel { - type = 'playlistPanelRenderer'; + type = 'PlaylistPanel'; constructor(data) { this.title = data.title; diff --git a/lib/parser/contents/classes/PlaylistPanelVideo.js b/lib/parser/contents/classes/PlaylistPanelVideo.js index c7e3138e6..a267bebe1 100644 --- a/lib/parser/contents/classes/PlaylistPanelVideo.js +++ b/lib/parser/contents/classes/PlaylistPanelVideo.js @@ -7,11 +7,11 @@ const NavigationEndpoint = require('./NavigationEndpoint'); const Utils = require('../../../utils/Utils'); class PlaylistPanelVideo { - type = 'playlistPanelVideoRenderer'; + type = 'PlaylistPanelVideo'; constructor(data) { this.title = new Text(data.title); - this.thumbnail = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnail = Thumbnail.fromResponse(data.thumbnail); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.selected = data.selected; this.video_id = data.videoId; diff --git a/lib/parser/contents/classes/PlaylistSidebar.js b/lib/parser/contents/classes/PlaylistSidebar.js new file mode 100644 index 000000000..5fe027bdf --- /dev/null +++ b/lib/parser/contents/classes/PlaylistSidebar.js @@ -0,0 +1,14 @@ +'use strict'; + +const Parser = require('..'); + +class PlaylistSidebar { + type = 'PlaylistSidebar'; + + constructor(data) { + this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency + } +} + +module.exports = PlaylistSidebar; \ No newline at end of file diff --git a/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.js b/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.js new file mode 100644 index 000000000..91b342251 --- /dev/null +++ b/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.js @@ -0,0 +1,18 @@ +const Parser = require('..'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class PlaylistSidebarPrimaryInfo { + type = 'PlaylistSidebarPrimaryInfo'; + + constructor(data) { + this.stats = data.stats.map(stat => new Text(stat)); + this.thumbnail_renderer = Parser.parse(data.thumbnailRenderer); + this.title = new Text(data.title); + this.menu = data.menu && Parser.parse(data.menu); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + this.description = new Text(data.description); + } +} + +module.exports = PlaylistSidebarPrimaryInfo; \ No newline at end of file diff --git a/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.js b/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.js new file mode 100644 index 000000000..442f06225 --- /dev/null +++ b/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.js @@ -0,0 +1,12 @@ +const Parser = require('..'); + +class PlaylistSidebarSecondaryInfo { + type = 'PlaylistSidebarSecondaryInfo'; + + constructor(data) { + this.owner = data.videoOwner && Parser.parse(data.videoOwner); + this.button = data.button && Parser.parse(data.button); + } +} + +module.exports = PlaylistSidebarSecondaryInfo; \ No newline at end of file diff --git a/lib/parser/contents/classes/PlaylistVideo.js b/lib/parser/contents/classes/PlaylistVideo.js index 45745cabb..4ae238c12 100644 --- a/lib/parser/contents/classes/PlaylistVideo.js +++ b/lib/parser/contents/classes/PlaylistVideo.js @@ -6,14 +6,14 @@ const PlaylistAuthor = require('./PlaylistAuthor'); const NavigationEndpoint = require('./NavigationEndpoint'); class PlaylistVideo { - type = 'playlistVideoRenderer'; + type = 'PlaylistVideo'; constructor(data) { this.id = data.videoId; this.index = new Text(data.index); this.title = new Text(data.title); this.author = new PlaylistAuthor({ nav_text: data.shortBylineText }); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.set_video_id = data?.setVideoId; this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.is_playable = data.isPlayable; diff --git a/lib/parser/contents/classes/PlaylistVideoList.js b/lib/parser/contents/classes/PlaylistVideoList.js index 059016d7e..9e0c25bdd 100644 --- a/lib/parser/contents/classes/PlaylistVideoList.js +++ b/lib/parser/contents/classes/PlaylistVideoList.js @@ -3,7 +3,7 @@ const Parser = require('..'); class PlaylistVideoList { - type = 'playlistVideoListRenderer'; + type = 'PlaylistVideoList'; constructor(data) { this.id = data.playlistId; diff --git a/lib/parser/contents/classes/PlaylistVideoThumbnail.js b/lib/parser/contents/classes/PlaylistVideoThumbnail.js new file mode 100644 index 000000000..43e995a45 --- /dev/null +++ b/lib/parser/contents/classes/PlaylistVideoThumbnail.js @@ -0,0 +1,11 @@ +const Thumbnail = require('./Thumbnail'); + +class PlaylistVideoThumbnail { + type = 'PlaylistVideoThumbnail'; + + constructor(data) { + this.thumbnail = Thumbnail.fromResponse(data.thumbnail); + } +} + +module.exports = PlaylistVideoThumbnail; \ No newline at end of file diff --git a/lib/parser/contents/classes/ProfileColumn.js b/lib/parser/contents/classes/ProfileColumn.js index 0baafcf63..c96e7de67 100644 --- a/lib/parser/contents/classes/ProfileColumn.js +++ b/lib/parser/contents/classes/ProfileColumn.js @@ -3,10 +3,11 @@ const Parser = require('..'); class ProfileColumn { - type = 'profileColumnRenderer'; + type = 'ProfileColumn'; constructor(data) { this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency } } diff --git a/lib/parser/contents/classes/ProfileColumnStats.js b/lib/parser/contents/classes/ProfileColumnStats.js index 48db5f439..7f50c78ff 100644 --- a/lib/parser/contents/classes/ProfileColumnStats.js +++ b/lib/parser/contents/classes/ProfileColumnStats.js @@ -3,10 +3,11 @@ const Parser = require('..'); class ProfileColumnStats { - type = 'profileColumnStatsRenderer'; + type = 'ProfileColumnStats'; constructor(data) { this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency } } diff --git a/lib/parser/contents/classes/ProfileColumnStatsEntry.js b/lib/parser/contents/classes/ProfileColumnStatsEntry.js index 0e14636b4..1b69380ef 100644 --- a/lib/parser/contents/classes/ProfileColumnStatsEntry.js +++ b/lib/parser/contents/classes/ProfileColumnStatsEntry.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class ProfileColumnStatsEntry { - type = 'profileColumnStatsEntryRenderer'; + type = 'ProfileColumnStatsEntry'; constructor(data) { this.label = new Text(data.label); diff --git a/lib/parser/contents/classes/ProfileColumnUserInfo.js b/lib/parser/contents/classes/ProfileColumnUserInfo.js index fdc7cbf68..c85502a81 100644 --- a/lib/parser/contents/classes/ProfileColumnUserInfo.js +++ b/lib/parser/contents/classes/ProfileColumnUserInfo.js @@ -4,11 +4,11 @@ const Text = require('./Text'); const Thumbnail = require('./Thumbnail'); class ProfileColumnUserInfo { - type = 'profileColumnUserInfoRenderer'; + type = 'ProfileColumnUserInfo'; constructor(data) { this.title = new Text(data.title); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); } } diff --git a/lib/parser/contents/classes/ReelItem.js b/lib/parser/contents/classes/ReelItem.js new file mode 100644 index 000000000..a4b844fad --- /dev/null +++ b/lib/parser/contents/classes/ReelItem.js @@ -0,0 +1,17 @@ +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); +const Thumbnail = require('./Thumbnail'); + +class ReelItem { + type = 'ReelItem'; + + constructor(data) { + this.id = data.videoId; + this.title = new Text(data.headline, ''); + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); + this.views = new Text(data.viewCountText, ''); + this.endpoint = new NavigationEndpoint(data.navigationEndpoint); + } +} + +module.exports = ReelItem; \ No newline at end of file diff --git a/lib/parser/contents/classes/ReelShelf.js b/lib/parser/contents/classes/ReelShelf.js new file mode 100644 index 000000000..8b95dfbfa --- /dev/null +++ b/lib/parser/contents/classes/ReelShelf.js @@ -0,0 +1,16 @@ +const Parser = require('..'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class ReelShelf { + type = 'ReelShelf'; + + constructor(data) { + this.title = new Text(data.title); + this.items = Parser.parse(data.items); + this.endpoint = data.endpoint ? new NavigationEndpoint(data.endpoint) : null; + this.contents = this.items; // XXX: alias for consistency + } +} + +module.exports = ReelShelf; \ No newline at end of file diff --git a/lib/parser/contents/classes/RelatedChipCloud.js b/lib/parser/contents/classes/RelatedChipCloud.js index a83ef9b73..939f503e2 100644 --- a/lib/parser/contents/classes/RelatedChipCloud.js +++ b/lib/parser/contents/classes/RelatedChipCloud.js @@ -3,7 +3,7 @@ const Parser = require('..'); class RelatedChipCloud { - type = 'relatedChipCloudRenderer'; + type = 'RelatedChipCloud'; constructor(data) { this.content = Parser.parse(data.content); diff --git a/lib/parser/contents/classes/RichGrid.js b/lib/parser/contents/classes/RichGrid.js new file mode 100644 index 000000000..bda58bb8a --- /dev/null +++ b/lib/parser/contents/classes/RichGrid.js @@ -0,0 +1,14 @@ +const Parser = require('..'); + +class RichGrid { + type = 'RichGrid'; + + constructor(data) { + // XXX: we don't parse the masthead since it is usually an advertisement + // XXX: reflowOptions aren't parsed, I think its only used internally for layout + this.header = Parser.parse(data.header); + this.contents = Parser.parse(data.contents); + } +} + +module.exports = RichGrid; \ No newline at end of file diff --git a/lib/parser/contents/classes/RichItem.js b/lib/parser/contents/classes/RichItem.js new file mode 100644 index 000000000..c823a5f50 --- /dev/null +++ b/lib/parser/contents/classes/RichItem.js @@ -0,0 +1,11 @@ +const Parser = require('..'); + +class RichItem { + type = 'RichItem'; + + constructor(data) { + this.content = Parser.parse(data.content); + } +} + +module.exports = RichItem; \ No newline at end of file diff --git a/lib/parser/contents/classes/RichSection.js b/lib/parser/contents/classes/RichSection.js new file mode 100644 index 000000000..511f0df5f --- /dev/null +++ b/lib/parser/contents/classes/RichSection.js @@ -0,0 +1,11 @@ +const Parser = require('..'); + +class RichSection { + type = 'RichSection'; + + constructor(data) { + this.contents = Parser.parse(data.contents); + } +} + +module.exports = RichSection; \ No newline at end of file diff --git a/lib/parser/contents/classes/RichShelf.js b/lib/parser/contents/classes/RichShelf.js new file mode 100644 index 000000000..e33baf8ee --- /dev/null +++ b/lib/parser/contents/classes/RichShelf.js @@ -0,0 +1,15 @@ +const Parser = require('..'); +const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); + +class RichShelf { + type = 'RichShelf'; + + constructor(data) { + this.title = new Text(data.title); + this.contents = Parser.parse(data.contents); + this.endpoint = data.endpoint ? new NavigationEndpoint(data.endpoint) : null; + } +} + +module.exports = RichShelf; \ No newline at end of file diff --git a/lib/parser/contents/classes/SearchRefinementCard.js b/lib/parser/contents/classes/SearchRefinementCard.js index 2d7427c5e..850cb79c7 100644 --- a/lib/parser/contents/classes/SearchRefinementCard.js +++ b/lib/parser/contents/classes/SearchRefinementCard.js @@ -5,10 +5,10 @@ const Thumbnail = require('./Thumbnail'); const Text = require('./Text'); class SearchRefinementCard { - type = 'searchRefinementCardRenderer'; + type = 'SearchRefinementCard'; constructor(data) { - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.endpoint = new NavigationEndpoint(data.searchEndpoint); this.query = new Text(data.query).toString(); } diff --git a/lib/parser/contents/classes/SectionList.js b/lib/parser/contents/classes/SectionList.js index acdc670d3..3020860d4 100644 --- a/lib/parser/contents/classes/SectionList.js +++ b/lib/parser/contents/classes/SectionList.js @@ -3,7 +3,7 @@ const Parser = require('..'); class SectionList { - type = 'sectionListRenderer'; + type = 'SectionList'; constructor(data) { this.target_id = data.targetId || null; diff --git a/lib/parser/contents/classes/Shelf.js b/lib/parser/contents/classes/Shelf.js index d013a378d..0613a186e 100644 --- a/lib/parser/contents/classes/Shelf.js +++ b/lib/parser/contents/classes/Shelf.js @@ -5,7 +5,7 @@ const Parser = require('..'); const NavigationEndpoint = require('./NavigationEndpoint'); class Shelf { - type = 'shelfRenderer'; + type = 'Shelf'; constructor(data) { this.title = new Text(data.title); diff --git a/lib/parser/contents/classes/ShowingResultsFor.js b/lib/parser/contents/classes/ShowingResultsFor.js index 6dcddb144..7fe5d9e2d 100644 --- a/lib/parser/contents/classes/ShowingResultsFor.js +++ b/lib/parser/contents/classes/ShowingResultsFor.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class ShowingResultsFor { - type = 'showingResultsForRenderer'; + type = 'ShowingResultsFor'; constructor(data) { this.corrected_query = new Text(data.correctedQuery); diff --git a/lib/parser/contents/classes/SimpleCardTeaser.js b/lib/parser/contents/classes/SimpleCardTeaser.js index 4e45dca91..46dd189ab 100644 --- a/lib/parser/contents/classes/SimpleCardTeaser.js +++ b/lib/parser/contents/classes/SimpleCardTeaser.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class SimpleCardTeaser { - type = 'simpleCardTeaserRenderer'; + type = 'SimpleCardTeaser'; constructor(data) { this.message = new Text(data.message); diff --git a/lib/parser/contents/classes/SingleActionEmergencySupport.js b/lib/parser/contents/classes/SingleActionEmergencySupport.js index c1ba24d63..bd543dbb7 100644 --- a/lib/parser/contents/classes/SingleActionEmergencySupport.js +++ b/lib/parser/contents/classes/SingleActionEmergencySupport.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class SingleActionEmergencySupport { - type = 'singleActionEmergencySupportRenderer'; + type = 'SingleActionEmergencySupport'; constructor(data) { this.action_text = new Text(data.actionText); diff --git a/lib/parser/contents/classes/SingleColumnBrowseResults.js b/lib/parser/contents/classes/SingleColumnBrowseResults.js index 5a1378953..e86325cbb 100644 --- a/lib/parser/contents/classes/SingleColumnBrowseResults.js +++ b/lib/parser/contents/classes/SingleColumnBrowseResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class SingleColumnBrowseResults { - type = 'singleColumnBrowseResultsRenderer'; + type = 'SingleColumnBrowseResults'; constructor(data) { this.tabs = Parser.parse(data.tabs); diff --git a/lib/parser/contents/classes/SingleColumnMusicWatchNextResults.js b/lib/parser/contents/classes/SingleColumnMusicWatchNextResults.js index 61c658aa2..248ea0d3f 100644 --- a/lib/parser/contents/classes/SingleColumnMusicWatchNextResults.js +++ b/lib/parser/contents/classes/SingleColumnMusicWatchNextResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class SingleColumnMusicWatchNextResults { - type = 'singleColumnMusicWatchNextResults'; + type = 'SingleColumnMusicWatchNextResults'; constructor(data) { return Parser.parse(data); diff --git a/lib/parser/contents/classes/SubscribeButton.js b/lib/parser/contents/classes/SubscribeButton.js index 3c979bcea..fb17b3e62 100644 --- a/lib/parser/contents/classes/SubscribeButton.js +++ b/lib/parser/contents/classes/SubscribeButton.js @@ -5,7 +5,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class SubscribeButton { - type = 'subscribeButtonRenderer'; + type = 'SubscribeButton'; constructor(data) { this.title = new Text(data.buttonText); diff --git a/lib/parser/contents/classes/SubscriptionNotificationToggleButton.js b/lib/parser/contents/classes/SubscriptionNotificationToggleButton.js index b2a970ee4..3d1b0c21f 100644 --- a/lib/parser/contents/classes/SubscriptionNotificationToggleButton.js +++ b/lib/parser/contents/classes/SubscriptionNotificationToggleButton.js @@ -3,7 +3,7 @@ const Parser = require('..'); class SubscriptionNotificationToggleButton { - type = 'subscriptionNotificationToggleButtonRenderer'; + type = 'SubscriptionNotificationToggleButton'; constructor(data) { this.states = data.states.map((state) => ({ diff --git a/lib/parser/contents/classes/Tab.js b/lib/parser/contents/classes/Tab.js index cd85ae0c8..a1fd7406b 100644 --- a/lib/parser/contents/classes/Tab.js +++ b/lib/parser/contents/classes/Tab.js @@ -4,7 +4,7 @@ const Parser = require('..'); const NavigationEndpoint = require('./NavigationEndpoint'); class Tab { - type = 'tabRenderer'; + type = 'Tab'; constructor(data) { this.title = data.title || 'N/A'; diff --git a/lib/parser/contents/classes/Tabbed.js b/lib/parser/contents/classes/Tabbed.js index ef4a87807..86ff61139 100644 --- a/lib/parser/contents/classes/Tabbed.js +++ b/lib/parser/contents/classes/Tabbed.js @@ -3,7 +3,7 @@ const Parser = require('..'); class Tabbed { - type = 'tabbedRenderer'; + type = 'Tabbed'; constructor(data) { return Parser.parse(data); diff --git a/lib/parser/contents/classes/TabbedSearchResults.js b/lib/parser/contents/classes/TabbedSearchResults.js index baa087be9..8be47b2a1 100644 --- a/lib/parser/contents/classes/TabbedSearchResults.js +++ b/lib/parser/contents/classes/TabbedSearchResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class TabbedSearchResults { - type = 'tabbedSearchResultsRenderer'; + type = 'TabbedSearchResults'; #data; diff --git a/lib/parser/contents/classes/Thumbnail.js b/lib/parser/contents/classes/Thumbnail.js index 463767764..b6a62f454 100644 --- a/lib/parser/contents/classes/Thumbnail.js +++ b/lib/parser/contents/classes/Thumbnail.js @@ -1,22 +1,33 @@ -'use strict'; - class Thumbnail { - type = 'thumbnail'; - - #data; - - constructor(data) { - this.#data = data; - - if (!data.hasOwnProperty('thumbnails')) { - this.url = data.url; - this.width = data.width; - this.height = data.height; - } + /** + * @type {string} + */ + url; + /** + * @type {number} + */ + width; + /** + * @type {number} + */ + height; + constructor ({ url, width, height }) { + this.url = url; + this.width = width; + this.height = height; } - - get thumbnails() { - return this.#data.thumbnails.map((thumbnail) => new Thumbnail(thumbnail)).sort((a, b) => b.width - a.width); + + /** + * Get thumbnails from response object + * + * @param {*} response response object + * @returns {Thumbnail[]} sorted array of thumbnails + */ + static fromResponse({ thumbnails }) { + if (!thumbnails) { + return; + } + return thumbnails.map(x => new Thumbnail(x)).sort((a, b) => b.width - a.width); } } diff --git a/lib/parser/contents/classes/ThumbnailOverlayBottomPanel.js b/lib/parser/contents/classes/ThumbnailOverlayBottomPanel.js index 3fdb6d8df..052ea5408 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayBottomPanel.js +++ b/lib/parser/contents/classes/ThumbnailOverlayBottomPanel.js @@ -1,7 +1,7 @@ 'use strict'; class ThumbnailOverlayBottomPanel { - type = 'thumbnailOverlayBottomPanelRenderer'; + type = 'ThumbnailOverlayBottomPanel'; constructor(data) { this.type = data.icon.iconType; diff --git a/lib/parser/contents/classes/ThumbnailOverlayHoverText.js b/lib/parser/contents/classes/ThumbnailOverlayHoverText.js index 4b5482bee..c839ddc4d 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayHoverText.js +++ b/lib/parser/contents/classes/ThumbnailOverlayHoverText.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class ThumbnailOverlayHoverText { - type = 'thumbnailOverlayHoverTextRenderer'; + type = 'ThumbnailOverlayHoverText'; constructor(data) { this.text = new Text(data.text); diff --git a/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.js b/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.js new file mode 100644 index 000000000..65be4ce27 --- /dev/null +++ b/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.js @@ -0,0 +1,13 @@ +'use strict'; + +const Text = require('./Text'); + +class ThumbnailOverlayLoadingPreview { + type = 'ThumbnailOverlayLoadingPreview'; + + constructor(data) { + this.text = new Text(data.text); + } +} + +module.exports = ThumbnailOverlayLoadingPreview; \ No newline at end of file diff --git a/lib/parser/contents/classes/ThumbnailOverlayNowPlaying.js b/lib/parser/contents/classes/ThumbnailOverlayNowPlaying.js index 9a9368c9f..38d5e1f5b 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayNowPlaying.js +++ b/lib/parser/contents/classes/ThumbnailOverlayNowPlaying.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class ThumbnailOverlayNowPlaying { - type = 'thumbnailOverlayNowPlayingRenderer'; + type = 'ThumbnailOverlayNowPlaying'; constructor(data) { this.text = new Text(data.text).text; diff --git a/lib/parser/contents/classes/ThumbnailOverlayPinking.js b/lib/parser/contents/classes/ThumbnailOverlayPinking.js index 54e8c78cb..46da97aaf 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayPinking.js +++ b/lib/parser/contents/classes/ThumbnailOverlayPinking.js @@ -1,7 +1,7 @@ 'use strict'; class ThumbnailOverlayPinking { - type = 'thumbnailOverlayPinkingRenderer'; + type = 'ThumbnailOverlayPinking'; constructor(data) { this.hack = data.hack; diff --git a/lib/parser/contents/classes/ThumbnailOverlayResumePlayback.js b/lib/parser/contents/classes/ThumbnailOverlayResumePlayback.js index 42bd69fbe..435d22aba 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayResumePlayback.js +++ b/lib/parser/contents/classes/ThumbnailOverlayResumePlayback.js @@ -1,7 +1,7 @@ 'use strict'; class ThumbnailOverlayResumePlayback { - type = 'thumbnailOverlayResumePlaybackRenderer'; + type = 'ThumbnailOverlayResumePlayback'; constructor(data) { this.percent_duration_watched = data.percentDurationWatched; diff --git a/lib/parser/contents/classes/ThumbnailOverlaySidePanel.js b/lib/parser/contents/classes/ThumbnailOverlaySidePanel.js index ce77837b6..3c0f53ae6 100644 --- a/lib/parser/contents/classes/ThumbnailOverlaySidePanel.js +++ b/lib/parser/contents/classes/ThumbnailOverlaySidePanel.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class ThumbnailOverlaySidePanel { - type = 'ThumbnailOverlaySidePanelRenderer'; + type = 'ThumbnailOverlaySidePanel'; constructor(data) { this.text = new Text(data.text); diff --git a/lib/parser/contents/classes/ThumbnailOverlayTimeStatus.js b/lib/parser/contents/classes/ThumbnailOverlayTimeStatus.js index 87010dcb5..f1c491052 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayTimeStatus.js +++ b/lib/parser/contents/classes/ThumbnailOverlayTimeStatus.js @@ -3,7 +3,7 @@ const Text = require('./Text'); class ThumbnailOverlayTimeStatus { - type = 'thumbnailOverlayTimeStatusRenderer'; + type = 'ThumbnailOverlayTimeStatus'; constructor(data) { this.text = new Text(data.text).text; diff --git a/lib/parser/contents/classes/ThumbnailOverlayToggleButton.js b/lib/parser/contents/classes/ThumbnailOverlayToggleButton.js index 3d1eb445e..6c24ca4df 100644 --- a/lib/parser/contents/classes/ThumbnailOverlayToggleButton.js +++ b/lib/parser/contents/classes/ThumbnailOverlayToggleButton.js @@ -3,7 +3,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class ThumbnailOverlayToggleButton { - type = 'thumbnailOverlayToggleButtonRenderer'; + type = 'ThumbnailOverlayToggleButton'; constructor(data) { this.is_toggled = data.isToggled || null; diff --git a/lib/parser/contents/classes/ToggleButton.js b/lib/parser/contents/classes/ToggleButton.js index 09a2156d3..112f8c7fb 100644 --- a/lib/parser/contents/classes/ToggleButton.js +++ b/lib/parser/contents/classes/ToggleButton.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class ToggleButton { - type = 'toggleButtonRenderer'; + type = 'ToggleButton'; constructor(data) { this.text = new Text(data.defaultText); @@ -19,10 +19,10 @@ class ToggleButton { (this.like_count = parseInt(data.defaultText.accessibility.accessibilityData.label.replace(/\D/g, ''))) && (this.short_like_count = new Text(data.defaultText).toString()); - this.endpoint = new NavigationEndpoint(data.defaultServiceEndpoint.commandExecutorCommand.commands.pop()); + this.endpoint = data.defaultServiceEndpoint?.commandExecutorCommand?.commands && new NavigationEndpoint(data.defaultServiceEndpoint.commandExecutorCommand.commands.pop()); this.toggled_endpoint = new NavigationEndpoint(data.toggledServiceEndpoint); - this.button_id = data.toggleButtonSupportedData.toggleButtonIdData.id; + this.button_id = data.toggleButtonSupportedData?.toggleButtonIdData?.id; this.target_id = data.targetId; } } diff --git a/lib/parser/contents/classes/ToggleMenuServiceItem.js b/lib/parser/contents/classes/ToggleMenuServiceItem.js index 4da766d23..5dd8cd180 100644 --- a/lib/parser/contents/classes/ToggleMenuServiceItem.js +++ b/lib/parser/contents/classes/ToggleMenuServiceItem.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class ToggleMenuServiceItem { - type = 'toggleMenuServiceItemRenderer'; + type = 'ToggleMenuServiceItem'; constructor(data) { this.text = new Text(data.defaultText); diff --git a/lib/parser/contents/classes/Tooltip.js b/lib/parser/contents/classes/Tooltip.js index 18c26b9e8..c63babba4 100644 --- a/lib/parser/contents/classes/Tooltip.js +++ b/lib/parser/contents/classes/Tooltip.js @@ -4,7 +4,7 @@ const Text = require('./Text'); const NavigationEndpoint = require('./NavigationEndpoint'); class Tooltip { - type = 'tooltipRenderer'; + type = 'Tooltip'; constructor(data) { this.promo_config = { diff --git a/lib/parser/contents/classes/TwoColumnBrowseResults.js b/lib/parser/contents/classes/TwoColumnBrowseResults.js index 29e14eb7b..8fe1ac292 100644 --- a/lib/parser/contents/classes/TwoColumnBrowseResults.js +++ b/lib/parser/contents/classes/TwoColumnBrowseResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class TwoColumnBrowseResults { - type = 'twoColumnBrowseResultsRenderer'; + type = 'TwoColumnBrowseResults'; constructor(data) { this.tabs = Parser.parse(data.tabs); diff --git a/lib/parser/contents/classes/TwoColumnSearchResults.js b/lib/parser/contents/classes/TwoColumnSearchResults.js index cf7b9e96a..f0fe799fd 100644 --- a/lib/parser/contents/classes/TwoColumnSearchResults.js +++ b/lib/parser/contents/classes/TwoColumnSearchResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class TwoColumnSearchResults { - type = 'twoColumnSearchResultsRenderer'; + type = 'TwoColumnSearchResults'; constructor(data) { this.primary_contents = Parser.parse(data.primaryContents); diff --git a/lib/parser/contents/classes/TwoColumnWatchNextResults.js b/lib/parser/contents/classes/TwoColumnWatchNextResults.js index 3b916c01e..17f83ed3c 100644 --- a/lib/parser/contents/classes/TwoColumnWatchNextResults.js +++ b/lib/parser/contents/classes/TwoColumnWatchNextResults.js @@ -3,7 +3,7 @@ const Parser = require('..'); class TwoColumnWatchNextResults { - type = 'twoColumnWatchNextResults'; + type = 'TwoColumnWatchNextResults'; constructor(data) { this.results = Parser.parse(data.results?.results.contents); diff --git a/lib/parser/contents/classes/VerticalList.js b/lib/parser/contents/classes/VerticalList.js index a52988698..9a0bec55d 100644 --- a/lib/parser/contents/classes/VerticalList.js +++ b/lib/parser/contents/classes/VerticalList.js @@ -4,10 +4,11 @@ const Parser = require('..'); const Text = require('./Text'); class VerticalList { - type = 'verticalListRenderer'; + type = 'VerticalList'; constructor(data) { this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency this.collapsed_item_count = data.collapsedItemCount; this.collapsed_state_button_text = new Text(data.collapsedStateButtonText); } diff --git a/lib/parser/contents/classes/VerticalWatchCardList.js b/lib/parser/contents/classes/VerticalWatchCardList.js index 21797a0b1..f5c51059a 100644 --- a/lib/parser/contents/classes/VerticalWatchCardList.js +++ b/lib/parser/contents/classes/VerticalWatchCardList.js @@ -9,6 +9,7 @@ class VerticalWatchCardList { constructor(data) { this.items = Parser.parse(data.items); + this.contents = this.items; // XXX: alias for consistency this.view_all_text = new Text(data.viewAllText); this.view_all_endpoint = new NavigationEndpoint(data.viewAllEndpoint); } diff --git a/lib/parser/contents/classes/Video.js b/lib/parser/contents/classes/Video.js index d5222bc11..2ddee596f 100644 --- a/lib/parser/contents/classes/Video.js +++ b/lib/parser/contents/classes/Video.js @@ -8,7 +8,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); const Utils = require('../../../utils/Utils'); class Video { - type = 'videoRenderer'; + type = 'Video'; constructor(data) { const overlay_time_status = data.thumbnailOverlays @@ -17,22 +17,23 @@ class Video { this.id = data.videoId; this.title = new Text(data.title); - this.description = new Text(data.descriptionSnippet || data.description); + this.description_snippet = data.descriptionSnippet ? new Text(data.descriptionSnippet, '') : null; this.snippets = data.detailedMetadataSnippets?.map((snippet) => ({ text: new Text(snippet.snippetText), hover_text: new Text(snippet.snippetHoverText), })) || []; - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; + this.thumbnails = Thumbnail.fromResponse(data.thumbnail); this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays); - this.moving_thumbnails = Parser.parse(data.richThumbnail)?.thumbnails || []; - this.channel_thumbnail = Parser.parse(data.channelThumbnailSupportedRenderers); - this.author = new Author({ nav_text: data.ownerText, badges: data.ownerBadges || data.badges }); + this.rich_thumbnail = data.richThumbnail && Parser.parse(data.richThumbnail); + this.author = new Author(data.ownerText, data.ownerBadges, data.channelThumbnailSupportedRenderers?.channelThumbnailWithLinkRenderer?.thumbnail); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.published = new Text(data.publishedTimeText); this.view_count_text = new Text(data.viewCountText); this.short_view_count_text = new Text(data.shortViewCountText); + const upcoming = data.upcomingEventData && Number(`${data.upcomingEventData.startTime}000`); + if (upcoming) this.upcoming = new Date(upcoming); this.duration = { text: data.lengthText ? new Text(data.lengthText).text : new Text(overlay_time_status).text, @@ -43,6 +44,47 @@ class Video { this.is_watched = data.isWatched || false; this.menu = Parser.parse(data.menu); } + + + /** + * @returns {string} + */ + get description() { + if (this.snippets.length > 0) { + return this.snippets.map(snip => snip.text.toString()).join('') + } + return this.description_snippet?.toString() || ''; + } + + + + /** + * @type {boolean} + */ + get is_live() { + return this.badges.some(badge => badge.style === 'BADGE_STYLE_TYPE_LIVE_NOW'); + } + + /** + * @type {boolean} + */ + get is_upcoming() { + return this.upcoming && this.upcoming > new Date(); + } + + /** + * @type {boolean} + */ + get has_captions() { + return this.badges.some(badge => badge.label === 'CC'); + } + + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail() { + return this.thumbnails[0]; + } } module.exports = Video; \ No newline at end of file diff --git a/lib/parser/contents/classes/VideoDetails.js b/lib/parser/contents/classes/VideoDetails.js index ee9826141..a1c469f62 100644 --- a/lib/parser/contents/classes/VideoDetails.js +++ b/lib/parser/contents/classes/VideoDetails.js @@ -3,23 +3,47 @@ const Thumbnail = require('./Thumbnail'); class VideoDetails { - constructor(data) { - this.id = data.videoId; - this.title = data.title; - this.duration = parseInt(data.lengthSeconds); - this.keywords = data.keywords || []; - this.channel_id = data.channelId; - this.is_owner_viewing = data.isOwnerViewing; - this.description = data.shortDescription; - this.is_crawlable = data.isCrawlable; - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; - this.allow_ratings = data.allowRatings; - this.view_count = parseInt(data.viewCount); - this.author = data.author; - this.is_private = data.isPrivate; - this.is_unplugged_corpus = data.isUnpluggedCorpus; - this.is_live_content = data.isLiveContent; - } + /** + * @type {string} + */ + id; + /** + * @type {string} + */ + channel_id; + /** + * @type {string} + */ + title; + /** + * @type {string[]} + */ + keywords; + /** + * @type {string} + */ + short_description; + /** + * @type {string} + */ + author; + + constructor(data) { + this.id = data.videoId; + this.channel_id = data.channelId; + this.title = data.title; + this.duration = parseInt(data.lengthSeconds); + this.keywords = data.keywords; + this.is_owner_viewing = !!data.isOwnerViewing; + this.short_description = data.shortDescription; + this.thumbnail = Thumbnail.fromResponse(data.thumbnail); + this.allow_ratings = !!data.allowRatings; + this.view_count = parseInt(data.viewCount); + this.author = data.author; + this.is_private = !!data.isPrivate; + this.is_live_content = !!data.isLiveContent; + this.is_crawlable = !!data.isCrawlable; + } } module.exports = VideoDetails; \ No newline at end of file diff --git a/lib/parser/contents/classes/VideoInfoCardContent.js b/lib/parser/contents/classes/VideoInfoCardContent.js index 36090ba31..c62b27aef 100644 --- a/lib/parser/contents/classes/VideoInfoCardContent.js +++ b/lib/parser/contents/classes/VideoInfoCardContent.js @@ -5,13 +5,13 @@ const Thumbnail = require('./Thumbnail'); const NavigationEndpoint = require('./NavigationEndpoint'); class VideoInfoCardContent { - type = 'videoInfoCardContentRenderer'; + type = 'VideoInfoCardContent'; constructor(data) { this.title = new Text(data.videoTitle); this.channel_name = new Text(data.channelName); this.view_count = new Text(data.viewCountText); - this.video_thumbnails = new Thumbnail(data.videoThumbnail).thumbnails; + this.video_thumbnails = Thumbnail.fromResponse(data.videoThumbnail); this.duration = new Text(data.lengthString); this.endpoint = new NavigationEndpoint(data.action); } diff --git a/lib/parser/contents/classes/VideoOwner.js b/lib/parser/contents/classes/VideoOwner.js index 42e581524..2389c991d 100644 --- a/lib/parser/contents/classes/VideoOwner.js +++ b/lib/parser/contents/classes/VideoOwner.js @@ -1,22 +1,18 @@ 'use strict'; -const Parser = require('..'); const Text = require('./Text'); -const Thumbnail = require('./Thumbnail'); -const NavigationEndpoint = require('./NavigationEndpoint'); +const Author = require('./Author'); class VideoOwner { - type = 'videoOwnerRenderer'; + type = 'VideoOwner'; constructor(data) { - this.name = new Text(data.title); - this.thumbnails = new Thumbnail(data.thumbnail).thumbnails; this.subscription_button = data.subscriptionButton; - this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.subscriber_count = new Text(data.subscriberCountText); - this.badges = Parser.parse(data.badges); - this.is_verified = this.badges?.some((badge) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED') || false; - this.is_verified_artist = this.badges?.some((badge) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED_ARTIST') || false; + this.author = new Author({ + ...data.title, + navigationEndpoint: data.navigationEndpoint + }, data.badges, data.thumbnail); } } diff --git a/lib/parser/contents/classes/VideoPrimaryInfo.js b/lib/parser/contents/classes/VideoPrimaryInfo.js index b306d82c9..8643ec946 100644 --- a/lib/parser/contents/classes/VideoPrimaryInfo.js +++ b/lib/parser/contents/classes/VideoPrimaryInfo.js @@ -4,7 +4,7 @@ const Parser = require('..'); const Text = require('./Text'); class VideoPrimaryInfo { - type = 'videoPrimaryInfoRenderer'; + type = 'VideoPrimaryInfo'; constructor(data) { this.title = new Text(data.title); diff --git a/lib/parser/contents/classes/VideoSecondaryInfo.js b/lib/parser/contents/classes/VideoSecondaryInfo.js index 9a10c9627..52bc3a6cd 100644 --- a/lib/parser/contents/classes/VideoSecondaryInfo.js +++ b/lib/parser/contents/classes/VideoSecondaryInfo.js @@ -4,7 +4,7 @@ const Parser = require('..'); const Text = require('./Text'); class VideoSecondaryInfo { - type = 'videoSecondaryInfoRenderer'; + type = 'VideoSecondaryInfo'; constructor(data) { this.owner = Parser.parse(data.owner); diff --git a/lib/parser/contents/classes/WatchCardRichHeader.js b/lib/parser/contents/classes/WatchCardRichHeader.js index 15fbadb3a..5d5cd5c0f 100644 --- a/lib/parser/contents/classes/WatchCardRichHeader.js +++ b/lib/parser/contents/classes/WatchCardRichHeader.js @@ -1,15 +1,16 @@ -'use strict'; - -const Text = require('./Text'); +const Author = require('./Author'); const NavigationEndpoint = require('./NavigationEndpoint'); +const Text = require('./Text'); class WatchCardRichHeader { type = 'WatchCardRichHeader'; - + constructor(data) { this.title = new Text(data.title); this.title_endpoint = new NavigationEndpoint(data.titleNavigationEndpoint); this.subtitle = new Text(data.subtitle); + this.author = new Author(data, [data.titleBadge], data.avatar); + this.author.name = this.title; this.style = data.style; } } diff --git a/lib/parser/contents/classes/WatchNextTabbedResults.js b/lib/parser/contents/classes/WatchNextTabbedResults.js index 0a33541d0..2356ae78a 100644 --- a/lib/parser/contents/classes/WatchNextTabbedResults.js +++ b/lib/parser/contents/classes/WatchNextTabbedResults.js @@ -3,7 +3,7 @@ const TwoColumnBrowseResults = require('./TwoColumnBrowseResults'); class WatchNextTabbedResults extends TwoColumnBrowseResults { - type = 'watchNextTabbedResultsRenderer'; + type = 'WatchNextTabbedResults'; constructor(data) { super(data); diff --git a/lib/parser/contents/index.js b/lib/parser/contents/index.js index bb6bfad3c..7ecb86644 100644 --- a/lib/parser/contents/index.js +++ b/lib/parser/contents/index.js @@ -31,11 +31,44 @@ class SectionListContinuation { } class Parser { + static #memo = new Map(); + static #clearMemo() { + Parser.#memo = null; + } + static #createMemo() { + Parser.#memo = new Map(); + } + static #addToMemo(classname, result) { + if (!Parser.#memo) return; + if (!Parser.#memo.has(classname)) return Parser.#memo.set(classname, [result]); + Parser.#memo.get(classname).push(result); + } + static parseResponse(data) { + // Memoize the response objects by classname + this.#createMemo(); + const contents = Parser.parse(data.contents); + const contents_memo = Parser.#memo; + // End of memoization + this.#clearMemo(); + + this.#createMemo(); + const on_response_received_actions = data.onResponseReceivedActions && Parser.parseRR(data.onResponseReceivedActions) || null; + const on_response_received_actions_memo = Parser.#memo; + this.#clearMemo(); + + this.#createMemo(); + const on_response_received_endpoints = data.onResponseReceivedEndpoints && Parser.parseRR(data.onResponseReceivedEndpoints) || null; + const on_response_received_endpoints_memo = Parser.#memo; + this.#clearMemo(); + return { - contents: Parser.parse(data.contents), - on_response_received_actions: data.onResponseReceivedActions && Parser.parseRR(data.onResponseReceivedActions) || null, - on_response_received_endpoints: data.onResponseReceivedEndpoints && Parser.parseRR(data.onResponseReceivedEndpoints) || null, + contents, + contents_memo, + on_response_received_actions, + on_response_received_actions_memo, + on_response_received_endpoints, + on_response_received_endpoints_memo, on_response_received_commands: data.onResponseReceivedCommands && Parser.parseRR(data.onResponseReceivedCommands) || null, /** @type {*} */ continuation_contents: data.continuationContents && Parser.parseLC(data.continuationContents) || null, @@ -109,7 +142,9 @@ class Parser { if (!this.shouldIgnore(classname)) { try { const TargetClass = require('./classes/' + classname); - results.push(new TargetClass(item[keys[0]])); + const result = new TargetClass(item[keys[0]]); + results.push(result); + this.#addToMemo(classname, result); } catch (err) { this.formatError({ classname, classdata: item[keys[0]], err }); } @@ -124,7 +159,9 @@ class Parser { if (!this.shouldIgnore(classname)) { try { const TargetClass = require('./classes/' + classname); - return new TargetClass(data[keys[0]]); + const result = new TargetClass(data[keys[0]]); + this.#addToMemo(classname, result); + return result; } catch (err) { this.formatError({ classname, classdata: data[keys[0]], err }); return null; diff --git a/lib/parser/youtube/Channel.js b/lib/parser/youtube/Channel.js new file mode 100644 index 000000000..c770671e4 --- /dev/null +++ b/lib/parser/youtube/Channel.js @@ -0,0 +1,47 @@ +const TabbedFeed = require('../../core/TabbedFeed'); + +class Channel extends TabbedFeed { + /** + * @type {import('../parser/contents/ChannelMetadata')} + */ + metadata; + + constructor(actions, data, already_parsed = false) { + super(actions, data, already_parsed); + this.metadata = this.page.metadata; + this.title = this.metadata.title || ''; + this.description = this.metadata.description || ''; + } + + getVideos() { + return this.getTab('Videos'); + } + + getPlaylists() { + return this.getTab('Playlists'); + } + + getHome() { + return this.getTab('Home'); + } + + getCommunity() { + return this.getTab('Community'); + } + + getChannels() { + return this.getTab('Channels'); + } + + /** + * Get the channel about page + * + * @returns {Promise} + */ + async getAbout() { + const target_tab = await this.getTab('About'); + return target_tab.memo.get('ChannelAboutFullMetadata')?.[0]; + } +} + +module.exports = Channel; \ No newline at end of file diff --git a/lib/parser/youtube/Playlist.js b/lib/parser/youtube/Playlist.js new file mode 100644 index 000000000..174ff21e3 --- /dev/null +++ b/lib/parser/youtube/Playlist.js @@ -0,0 +1,47 @@ +const Feed = require('../../core/Feed'); + +class Playlist extends Feed { + constructor(actions, data, already_parsed = false) { + super(actions, data, already_parsed); + this.primary_info = this.memo.get('PlaylistSidebarPrimaryInfo')?.[0]; + } + + #getStat(index) { + if (!this.primary_info || !this.primary_info.stats) + return 'N/A'; + return this.primary_info.stats[index]?.toString() || 'N/A'; + } + + get title() { + if (!this.primary_info) + return ''; + return this.primary_info.title.toString(); + } + + get description() { + if (!this.primary_info) + return ''; + return this.primary_info.description.toString(); + } + + get total_items() { + return this.#getStat(0); + } + + get views() { + return this.#getStat(1); + } + + get last_updated() { + return this.#getStat(2); + } + + /** + * @alias videos + */ + get items () { + return this.videos; + } +} + +module.exports = Playlist; diff --git a/lib/parser/youtube/Search.js b/lib/parser/youtube/Search.js index f8dd91266..345397715 100644 --- a/lib/parser/youtube/Search.js +++ b/lib/parser/youtube/Search.js @@ -1,47 +1,31 @@ 'use strict'; -const Parser = require('../contents'); -const { InnertubeError, observe } = require('../../utils/Utils'); +const Feed = require('../../core/Feed'); +const { InnertubeError } = require('../../utils/Utils'); /** @namespace */ -class Search { - #page; - #actions; - #continuation; - +class Search extends Feed { /** - * @param {object} response - API response. * @param {import('../../core/Actions')} actions - * @param {object} [args] - * @param {boolean} [args.is_continuation] + * @param {object} data - API response data. + * @param {boolean} [already_parsed] - already parsed response. */ - constructor(response, actions, args = {}) { - this.#actions = actions; - - this.#page = args.is_continuation - && response - || Parser.parseResponse(response.data); + constructor(actions, data, already_parsed = false) { + super(actions, data, already_parsed); - const contents = this.#page.contents?.primary_contents.contents - || this.#page.on_response_received_commands[0].continuation_items; + const contents = this.page.contents?.primary_contents.contents + || this.page.on_response_received_commands[0].continuation_items; - const secondary_contents = this.#page.contents?.secondary_contents?.contents; + const secondary_contents = this.page.contents?.secondary_contents?.contents; /** @type {object[]} */ - this.results = contents.get({ type: 'itemSectionRenderer' }).contents; + this.results = contents.get({ type: 'ItemSection' }).contents; - const shelves = this.results.findAll({ type: 'shelfRenderer' }, true); - const card_list = this.results.get({ type: 'horizontalCardListRenderer' }, true); + const card_list = this.results.get({ type: 'HorizontalCardList' }, true); const universal_watch_card = secondary_contents?.get({ type: 'UniversalWatchCard' }); - this.refinements = this.#page.refinements || []; - this.estimated_results = this.#page.estimated_results; - - /** @type {{ sections: { title: string, items: object[] }[] }} */ - this.sections = observe(shelves.map((shelf) => ({ - title: shelf.title.toString(), - items: shelf.content.items - }))); + this.refinements = this.page.refinements || []; + this.estimated_results = this.page.estimated_results; this.watch_card = { /** @type {import('../contents/classes/UniversalWatchCard')} */ @@ -58,25 +42,13 @@ class Search { /** @type {import('../contents/classes/SearchRefinementCard')} */ cards: card_list?.cards || [] }; - - this.#continuation = contents.get({ type: 'continuationItemRenderer' }); - } - - /** - * Retrieves next batch of results. - * - * @returns {Promise.} - */ - async getContinuation() { - const response = await this.#continuation.endpoint.call(this.#actions); - return new Search(response, this.#actions, { is_continuation: true }); } /** - * Applies given refinement card and returns a new {@link Search} object. + * Applies given refinement card and returns a new {@link Feed} object. * * @param {import('../contents/classes/SearchRefinementCard') | string} card - refinement card object or query - * @returns {Promise.} + * @returns {Promise.} */ async selectRefinementCard(card) { let target_card; @@ -87,39 +59,20 @@ class Search { throw new InnertubeError('Refinement card not found!', { available_cards: this.refinement_card_queries } ); - } else if (card.type === 'searchRefinementCardRenderer') { + } else if (card.type === 'SearchRefinementCard') { target_card = card; } else { throw new InnertubeError('Invalid refinement card!'); } - const page = await target_card.endpoint.call(this.#actions); - return new Search(page, this.#actions, { is_continuation: true }); - } - - /** @type {boolean} */ - get has_continuation() { - return !!this.#continuation; + const page = await target_card.endpoint.call(this.actions); + return new Feed(this.actions, page, true); } /** @type {string[]} */ get refinement_card_queries() { return this.refinement_cards.cards.map((card) => card.query); } - - /** @type {import('../contents/classes/Video')[]} */ - get videos() { - return this.results.findAll({ type: 'videoRenderer' }); - } - - /** @type {import('../contents/classes/Playlist')[]} */ - get playlists() { - return this.results.findAll({ type: 'playlistRenderer' }); - } - - get page() { - return this.#page; - } } module.exports = Search; \ No newline at end of file diff --git a/lib/parser/youtube/VideoInfo.js b/lib/parser/youtube/VideoInfo.js index e4eea580c..f3461d01f 100644 --- a/lib/parser/youtube/VideoInfo.js +++ b/lib/parser/youtube/VideoInfo.js @@ -8,9 +8,9 @@ class VideoInfo { #page; #actions; #player; - + #watch_next_continuation; - + /** * @param {object} data - API response. * @param {import('../../core/Actions')} actions @@ -19,15 +19,15 @@ class VideoInfo { constructor(data, actions, player) { this.#actions = actions; this.#player = player; - + const info = Parser.parseResponse(data[0]); const next = Parser.parseResponse(data[1].data); - - this.#page = [ info, next ]; - + + this.#page = [info, next]; + if (info.playability_status.status === 'ERROR') throw new InnertubeError('This video is unavailable', info.playability_status); - + /** * @type {import('../contents/classes/VideoDetails')} */ @@ -38,62 +38,62 @@ class VideoInfo { * Microformat is a bit redundant, so only * a few things there are interesting to us. */ - embed: info.microformat.embed, + embed: info.microformat.embed, channel: info.microformat.channel, is_unlisted: info.microformat.is_unlisted, is_family_safe: info.microformat.is_family_safe, has_ypc_metadata: info.microformat.has_ypc_metadata } }; - + const results = next.contents.results; const secondary_results = next.contents.secondary_results; - + /** * @type {import('../contents/classes/VideoPrimaryInfo')} */ - this.primary_info = results.get({ type: 'videoPrimaryInfoRenderer' }); - + this.primary_info = results.get({ type: 'VideoPrimaryInfo' }); + /** * @type {import('../contents/classes/VideoSecondaryInfo')} */ - this.secondary_info = results.get({ type: 'videoSecondaryInfoRenderer' }); - + this.secondary_info = results.get({ type: 'VideoSecondaryInfo' }); + /** * @type {import('../contents/classes/MerchandiseShelf')} */ - this.merchandise = results?.get({ type: 'merchandiseShelfRenderer' }) || null; - + this.merchandise = results?.get({ type: 'MerchandiseShelf' }) || null; + /** * @type {import('../contents/classes/ChipCloud')} */ - this.related_chip_cloud = secondary_results?.get({ type: 'relatedChipCloudRenderer' }).content; - - this.watch_next_feed = secondary_results?.get({ target_id: 'watch-next-feed' }).contents; + this.related_chip_cloud = secondary_results?.get({ type: 'RelatedChipCloud' })?.content; + + this.watch_next_feed = secondary_results?.get({ target_id: 'watch-next-feed' })?.contents; this.#watch_next_continuation = this.watch_next_feed?.pop(); - + /** * @type {import('../contents/classes/PlayerOverlay')} */ this.player_overlays = next.player_overlays; - + this.basic_info.like_count = this.primary_info.menu.top_level_buttons.get({ icon_type: 'LIKE' }).like_count; this.basic_info.is_liked = this.primary_info.menu.top_level_buttons.get({ icon_type: 'LIKE' }).is_toggled; this.basic_info.is_disliked = this.primary_info.menu.top_level_buttons.get({ icon_type: 'DISLIKE' }).is_toggled; - + this.streaming_data = info.streaming_data || null; this.playability_status = info.playability_status; - + /** * @type {import('../contents/classes/PlayerAnnotationsExpanded')[]} */ this.annotations = info.annotations; - + /** * @type {import('../contents/classes/PlayerStoryboardSpec')} */ this.storyboards = info.storyboards; - + /** * @type {import('../contents/classes/Endscreen')} */ @@ -103,20 +103,20 @@ class VideoInfo { * @type {import('../contents/classes/PlayerCaptionsTracklist')} */ this.captions = info.captions; - + /** * @type {import('../contents/classes/CardCollection')} */ this.cards = info.cards; - + const comments_entry_point = results.get({ target_id: 'comments-entry-point' }); - + /** * @type {import('../contents/classes/CommentsEntryPointHeader')} */ - this.comments_entry_point_header = comments_entry_point?.contents.get({ type: 'commentsEntryPointHeaderRenderer' }) || {}; + this.comments_entry_point_header = comments_entry_point?.contents.get({ type: 'CommentsEntryPointHeader' }) || {}; } - + /** * Applies given filter to the watch next feed. * @@ -126,15 +126,15 @@ class VideoInfo { async selectFilter(name) { if (!this.filters.includes(name)) throw new InnertubeError('Invalid filter', { available_filters: this.filters }); - + const filter = this.related_chip_cloud.chips.get({ text: name }); if (filter.is_selected) return this; - + const response = await filter.endpoint.call(this.#actions); const data = response.on_response_received_endpoints.get({ target_id: 'watch-next-feed' }); this.watch_next_feed = data.continuation_items; - + return this; } @@ -149,19 +149,19 @@ class VideoInfo { async getWatchNextContinuation() { const response = await this.#watch_next_continuation.endpoint.call(this.#actions); const data = response.on_response_received_endpoints.get({ type: 'appendContinuationItemsAction' }); - + this.watch_next_feed = data.continuation_items; this.#watch_next_continuation = this.watch_next_feed.pop(); - + return this.watch_next_feed; } - + /** * API response. * * @typedef {{ success: boolean, status_code: number, data: object }} Response */ - + /** * Likes the video. * @@ -169,13 +169,13 @@ class VideoInfo { */ async like() { const button = this.primary_info.menu.top_level_buttons.get({ button_id: 'TOGGLE_BUTTON_ID_TYPE_LIKE' }); - if (button.is_toggled) throw new InnertubeError('This video already liked', { video_id: this.basic_info.id }); - + if (button.is_toggled) throw new InnertubeError('This video is already liked', { video_id: this.basic_info.id }); + const response = await button.endpoint.call(this.#actions); - + return response; } - + /** * Dislikes the video. * @@ -184,12 +184,12 @@ class VideoInfo { async dislike() { const button = this.primary_info.menu.top_level_buttons.get({ button_id: 'TOGGLE_BUTTON_ID_TYPE_DISLIKE' }); if (button.is_toggled) throw new InnertubeError('This video is already disliked', { video_id: this.basic_info.id }); - + const response = await button.endpoint.call(this.#actions); - + return response; } - + /** * Removes like/dislike. * @@ -198,20 +198,52 @@ class VideoInfo { async removeLike() { const button = this.primary_info.menu.top_level_buttons.get({ is_toggled: true }); if (!button) throw new InnertubeError('This video is not liked/disliked', { video_id: this.basic_info.id }); - + const response = await button.toggled_endpoint.call(this.#actions); - + return response; } - + /** @type {string[]} */ get filters() { - return this.related_chip_cloud?.chips.map((chip) => chip.text) || []; + return this.related_chip_cloud?.chips.map((chip) => chip.text.toString()) || []; } - + get page() { return this.#page; } + + /** + * Get songs used in the video. + */ + get music_tracks() { + /** + * @type {import('../parser/contents/MetadataRowContainer')} + */ + const metadata = this.secondary_info.metadata; + if (!metadata) return []; + const songs = []; + let current_song = {}; + let is_music_section = false; + for (let i = 0; i < metadata.rows.length; i++) { + const row = metadata.rows[i]; + if (row.type === 'MetadataRowHeader') { + if (row.content.toString().toLowerCase().startsWith('music')) { + is_music_section = true; + i++; // skip the learn more link + } + continue; + } + if (!is_music_section) continue; + current_song[row.title.toString().toLowerCase().replace(/ /g, '_')] = row.contents; + if (row.has_divider_line) { + songs.push(current_song); + current_song = {}; + } + } + if (is_music_section) songs.push(current_song); + return songs; + } } module.exports = VideoInfo; \ No newline at end of file diff --git a/test/main.test.js b/test/main.test.js index 0ef8ecc4d..1810c86fe 100644 --- a/test/main.test.js +++ b/test/main.test.js @@ -73,7 +73,7 @@ describe('YouTube.js Tests', () => { it('Should retrieve trending content', async () => { const trending = await this.session.getTrending(); - expect(trending.now.content[0].videos.length).toBeLessThanOrEqual(100); + expect(trending.videos.length).toBeGreaterThan(0); }); it('Should retrieve video info', async () => { diff --git a/typings/lib/Innertube.d.ts b/typings/lib/Innertube.d.ts index 21895cdd2..0c268383e 100644 --- a/typings/lib/Innertube.d.ts +++ b/typings/lib/Innertube.d.ts @@ -128,7 +128,7 @@ declare class Innertube { metadata: object; }>; /** - * Retrieves comments for a given video. + * Retrieves comments for a video. * * @param {string} video_id - the video id. * @param {string} [sort_by] - can be: `TOP_COMMENTS` or `NEWEST_FIRST`. @@ -143,14 +143,9 @@ declare class Innertube { * Retrieves contents for a given channel. (WIP) * * @param {string} id - channel id - * @returns {Promise.<{ title: string, description: string, metadata: object, content: object }>} + * @returns {Promise} */ - getChannel(id: string): Promise<{ - title: string; - description: string; - metadata: object; - content: object; - }>; + getChannel(id: string): Promise; /** * Retrieves watch history. * @@ -163,43 +158,17 @@ declare class Innertube { }>; }>; /** - * Retrieves home feed (aka recommendations). + * Retrieves YouTube's home feed (aka recommendations). * - * @returns {Promise.<{ videos: Array.<{ id: string, title: string, description: string, channel: string, metadata: object }>}>} + * @returns {Promise} */ - getHomeFeed(): Promise<{ - videos: Array<{ - id: string; - title: string; - description: string; - channel: string; - metadata: object; - }>; - }>; + getHomeFeed(): Promise; /** * Retrieves trending content. * - * @returns {Promise.<{ now: { content: Array.<{ title: string, videos: object[] }> }, - * music: { getVideos: Promise.> }, gaming: { getVideos: Promise.> }, - * movies: { getVideos: Promise.> } }>} + * @returns {Promise} */ - getTrending(): Promise<{ - now: { - content: Array<{ - title: string; - videos: object[]; - }>; - }; - music: { - getVideos: Promise>; - }; - gaming: { - getVideos: Promise>; - }; - movies: { - getVideos: Promise>; - }; - }>; + getTrending(): Promise; /** * @todo finish this * WIP @@ -314,6 +283,7 @@ declare class Innertube { end: number; }; }): Stream.PassThrough; + getPlayer(): any; /** @readonly */ readonly get axios(): any; #private; @@ -328,4 +298,7 @@ import InteractionManager = require("./core/InteractionManager"); import YTMusic = require("./core/Music"); import VideoInfo = require("./parser/youtube/VideoInfo"); import Search = require("./parser/youtube/Search"); +import Channel = require("./parser/youtube/Channel"); +import FilterableFeed = require("./core/FilterableFeed"); +import TabbedFeed = require("./core/TabbedFeed"); import Stream = require("stream"); diff --git a/typings/lib/core/Channel.d.ts b/typings/lib/core/Channel.d.ts new file mode 100644 index 000000000..bcee4192a --- /dev/null +++ b/typings/lib/core/Channel.d.ts @@ -0,0 +1,84 @@ +export = Channel; +declare class Channel { + constructor(session: any, data: any); + get page(): { + contents: any; + on_response_received_actions: any; + on_response_received_endpoints: any; + on_response_received_commands: any; + continuation_contents: any; + metadata: any; + header: any; + microformat: import("../parser/contents/classes/PlayerMicroformat"); + sidebar: any; + overlay: any; + refinements: any; + estimated_results: any; + player_overlays: any; + playability_status: { + status: number; + error_screen: any; + embeddable: boolean; + reason: string; + }; + streaming_data: { + expires: Date; + formats: import("../parser/contents/classes/Format")[]; + adaptive_formats: import("../parser/contents/classes/Format")[]; + dash_manifest_url: any; + dls_manifest_url: any; + }; + captions: any; + video_details: import("../parser/contents/classes/VideoDetails"); + annotations: any; + storyboards: any; + endscreen: import("../parser/contents/classes/Endscreen"); + cards: import("../parser/contents/classes/CardCollection"); + }; + get title(): any; + get description(): any; + /** + * @type {import('../parser/contents/ChannelMetadata')} + */ + get metadata(): import("../parser/contents/ChannelMetadata"); + /** + * + * @returns {import('../parser/contents/Tab')[]} + */ + getTabs(): import('../parser/contents/Tab')[]; + /** + * + * @param {string} name + * @returns {import('../parser/contents/Tab')} + */ + getTab(name: string): import('../parser/contents/Tab'); + getFeedFromTab(tab: any): Promise; + getVideos(): Promise; + getPlaylists(): Promise; + getHome(): Promise; + getCommunity(): Promise; + getChannels(): Promise; + /** + * Get the channel about page + * @returns {Promise} + */ + getAbout(): Promise; + /** + * @note home_page only returns videos! + * @deprecated use getXXX family of functions instead + */ + get content(): { + home_page: { + title: string; + content: any; + }[]; + getHome: any; + getVideos: any; + getPlaylists: any; + getCommunity: any; + getChannels: any; + getAbout: any; + }; + #private; +} +import Feed = require("./Feed"); diff --git a/typings/lib/core/Feed.d.ts b/typings/lib/core/Feed.d.ts new file mode 100644 index 000000000..e0348db13 --- /dev/null +++ b/typings/lib/core/Feed.d.ts @@ -0,0 +1,55 @@ +export = Feed; +declare class Feed { + /** + * Get all videos on a given page via memo + * + * @param {*} page + * @param memo + * @returns {Array} + */ + static getVideosFromMemo(memo: any): Array; + /** + * Get all playlists on a given page via memo + * + * @param {*} page + * @param memo + * @returns {Array} + */ + static getPlaylistsFromMemo(memo: any): Array; + constructor(actions: any, data: any, already_parsed?: boolean); + memo: any; + /** + * Get the original page data + */ + get page(): any; + get actions(): import("../core/Actions"); + /** + * Get all the videos in the feed + */ + get videos(): (import("../parser/contents/classes/PlaylistPanelVideo") | import("../parser/contents/classes/CompactVideo") | import("../parser/contents/classes/Video") | import("../parser/contents/classes/GridVideo") | import("../parser/contents/classes/PlaylistVideo") | import("../parser/contents/classes/WatchCardCompactVideo"))[]; + /** + * Get all playlists in the feed + * + * @returns {Array} + */ + get playlists(): (import("../parser/contents/classes/Playlist") | import("../parser/contents/classes/GridPlaylist"))[]; + /** + * Get all the community posts in the feed + * + * @returns {import('../parser/contents/classes/BackstagePost')[]} + */ + get backstage_posts(): import("../parser/contents/classes/BackstagePost")[]; + /** + * Get all the channels in the feed + * + * @returns {Array} + */ + get channels(): any[]; + get has_continuation(): boolean; + getContinuationData(): any; + get shelves(): any; + getShelf(title: any): any; + get shelf_content(): any; + getContinuation(): Promise; + #private; +} diff --git a/typings/lib/core/FilterableFeed.d.ts b/typings/lib/core/FilterableFeed.d.ts new file mode 100644 index 000000000..d63637d02 --- /dev/null +++ b/typings/lib/core/FilterableFeed.d.ts @@ -0,0 +1,13 @@ +export = FilterableFeed; +declare class FilterableFeed extends Feed { + /** + * Get filters for the feed + * + * @returns {import('../parser/contents/ChipCloudChip')[]} + */ + get filter_chips(): any[]; + get filters(): any[]; + getFilteredFeed(name: any): Promise; + #private; +} +import Feed = require("./Feed"); diff --git a/typings/lib/core/HomeFeed.d.ts b/typings/lib/core/HomeFeed.d.ts new file mode 100644 index 000000000..0575be434 --- /dev/null +++ b/typings/lib/core/HomeFeed.d.ts @@ -0,0 +1,12 @@ +export = HomeFeed; +declare class HomeFeed extends Feed { + constructor(session: any, data: any); + /** + * Get filters for the home feed + * @returns {import('../parser/contents/ChipCloudChip')[]} + */ + getFeedFilters(): import('../parser/contents/ChipCloudChip')[]; + getContinuation(): Promise; + #private; +} +import Feed = require("./Feed"); diff --git a/typings/lib/core/Playlist.d.ts b/typings/lib/core/Playlist.d.ts new file mode 100644 index 000000000..48c386db9 --- /dev/null +++ b/typings/lib/core/Playlist.d.ts @@ -0,0 +1,20 @@ +export = Playlist; +declare class Playlist extends Feed { + constructor(session: any, data: any, client: any); + /** + * @returns {import('../parser/contents/PlaylistSidebarPrimaryInfo') | undefined} + */ + getPrimaryInfo(): import('../parser/contents/PlaylistSidebarPrimaryInfo') | undefined; + get title(): string; + get description(): string; + get total_items(): any; + get views(): any; + get last_updated(): any; + /** + * @alias videos + */ + get items(): import("./VideoItem")[]; + getContinuation(): Promise; + #private; +} +import Feed = require("./Feed"); diff --git a/typings/lib/core/PlaylistItem.d.ts b/typings/lib/core/PlaylistItem.d.ts new file mode 100644 index 000000000..11d5e9294 --- /dev/null +++ b/typings/lib/core/PlaylistItem.d.ts @@ -0,0 +1,25 @@ +export = SimplePlaylist; +/** + * Wraps around: + * - Playlist + * - GridPlaylist + * + * Provides a unified interface for all of them. + * + * TODO: refactor - name this PlaylistItem + */ +declare class SimplePlaylist { + static get regex(): RegExp; + /** + * Wrap around a playlist + * @param {import('../parser/contents/Playlist') | import('../parser/contents/GridPlaylist')} playlist + */ + constructor(playlist: import('../parser/contents/Playlist') | import('../parser/contents/GridPlaylist')); + get id(): any; + get title(): string; + get thumbnail(): any; + get thumbnails(): any; + get video_thumbnails(): any; + get author(): any; + #private; +} diff --git a/typings/lib/core/SimplePlaylist.d.ts b/typings/lib/core/SimplePlaylist.d.ts new file mode 100644 index 000000000..06935e01a --- /dev/null +++ b/typings/lib/core/SimplePlaylist.d.ts @@ -0,0 +1,23 @@ +export = SimplePlaylist; +/** + * Wraps around: + * - Playlist + * - GridPlaylist + * + * Provides a unified interface for all of them. + */ +declare class SimplePlaylist { + static get regex(): RegExp; + /** + * Wrap around a playlist + * @param {import('../parser/contents/Playlist') | import('../parser/contents/GridPlaylist')} playlist + */ + constructor(playlist: import('../parser/contents/Playlist') | import('../parser/contents/GridPlaylist')); + get id(): any; + get title(): string; + get thumbnail(): any; + get thumbnails(): any; + get video_thumbnails(): any; + get author(): any; + #private; +} diff --git a/typings/lib/core/SimpleVideo.d.ts b/typings/lib/core/SimpleVideo.d.ts new file mode 100644 index 000000000..fbe5b9331 --- /dev/null +++ b/typings/lib/core/SimpleVideo.d.ts @@ -0,0 +1,41 @@ +export = SimpleVideo; +/** + * Wraps around: + * - Video + * - GridVideo + * - CompactVideo + * - PlaylistVideo + * - PlaylistPanelVideo + * - TODO: WatchCardCompactVideo + * + * Provides a unified interface for all of them. + */ +declare class SimpleVideo { + static get regex(): RegExp; + constructor(video: any); + getUnderlyingRenderer(): import("../parser/contents/Video") | import("../parser/contents/GridVideo") | import("../parser/contents/PlaylistVideo") | import("../parser/contents/CompactVideo") | import("../parser/contents/PlaylistPanelVideo"); + get id(): any; + get title(): string; + get description(): any; + get channel(): import("../parser/contents/Author"); + get metadata(): { + view_count: any; + short_view_count_text: { + simple_text: any; + accessibility_label: string; + }; + thumbnail: import("../parser/contents/Thumbnail"); + thumbnails: import("../parser/contents/Thumbnail")[]; + moving_thumbnail: any; + moving_thumbnails: any; + published: any; + duration: { + seconds: number; + simple_text: string; + accessibility_label: string; + }; + badges: any; + owner_badges: string[]; + }; + #private; +} diff --git a/typings/lib/core/TabbedFeed.d.ts b/typings/lib/core/TabbedFeed.d.ts new file mode 100644 index 000000000..566673871 --- /dev/null +++ b/typings/lib/core/TabbedFeed.d.ts @@ -0,0 +1,13 @@ +export = TabbedFeed; +declare class TabbedFeed extends Feed { + get tabs(): any[]; + /** + * + * @param {string} title title of the tab to get + * @returns + */ + getTab(title: string): Promise; + get title(): any; + #private; +} +import Feed = require("./Feed"); diff --git a/typings/lib/core/Trending.d.ts b/typings/lib/core/Trending.d.ts new file mode 100644 index 000000000..0601d88c0 --- /dev/null +++ b/typings/lib/core/Trending.d.ts @@ -0,0 +1,86 @@ +export class Trending { + constructor(session: any, data: any); + /** + * + * @param {string} title title of the tab to get + * @returns + */ + getTab(title: string): TrendingTab; + /** + * @alias getTab('now') + */ + get now(): TrendingTab; + /** + * @alias getTab('music') + */ + get music(): TrendingTab; + get page(): { + contents: any; + on_response_received_actions: any; + on_response_received_endpoints: any; + on_response_received_commands: any; + continuation_contents: any; + metadata: any; + header: any; + microformat: import("../parser/contents/classes/PlayerMicroformat"); + sidebar: any; + overlay: any; + refinements: any; + estimated_results: any; + player_overlays: any; + playability_status: { + status: number; + error_screen: any; + embeddable: boolean; + reason: string; + }; + streaming_data: { + expires: Date; + formats: import("../parser/contents/classes/Format")[]; + adaptive_formats: import("../parser/contents/classes/Format")[]; + dash_manifest_url: any; + dls_manifest_url: any; + }; + captions: any; + video_details: import("../parser/contents/classes/VideoDetails"); + annotations: any; + storyboards: any; + endscreen: import("../parser/contents/classes/Endscreen"); + cards: import("../parser/contents/classes/CardCollection"); + }; + #private; +} +export class TrendingTab { + /** + * @param {import('../parser/contents/Tab')} tab + */ + constructor(session: any, tab: import('../parser/contents/Tab')); + get title(): string; + /** + * @returns {import('../parser/contents/Shelf')[]} + */ + getShelfs(): import('../parser/contents/Shelf')[]; + getShelf(title: any): any; + /** + * @type {{ + * title: string, + * videos: SimpleVideo[] + * }[] | null} + */ + get content(): { + title: string; + videos: SimpleVideo[]; + }[]; + /** + * Selects this tab and returns a new TrendingTab with this tab selected + */ + getSelected(): Promise; + /** + * @note getVideos returns only the vidoes of the first shelf + * @returns {SimpleVideo[]} + */ + getVideos(): SimpleVideo[]; + get raw(): import("../parser/contents/Tab"); + #private; +} +import SimpleVideo = require("./VideoItem"); diff --git a/typings/lib/core/Video.d.ts b/typings/lib/core/Video.d.ts new file mode 100644 index 000000000..d21991233 --- /dev/null +++ b/typings/lib/core/Video.d.ts @@ -0,0 +1,62 @@ +export = Video; +declare class Video { + constructor(session: any, player: any, page: any); + get id(): any; + get title(): any; + get description(): any; + get thumbnail(): any; + get metadata(): void; + get captions(): void; + get storyboards(): void; + getFormatURL(): any; + /** + * Get songs used in the video. + * @returns {{ [key: string]: import('../parser/contents/Text')[] }[]} + */ + get music_tracks(): { + [key: string]: import("../parser/contents/Text")[]; + }[]; + like(): void; + dislike(): void; + removeLike(): void; + unsubscribe(): void; + comment(): void; + getComments(): void; + getLivechat(): void; + setNotificationPreferences(): void; + get player(): { + contents: any; + on_response_received_actions: any; + on_response_received_endpoints: any; + on_response_received_commands: any; + continuation_contents: any; + metadata: any; + header: any; + microformat: import("../parser/contents/classes/PlayerMicroformat"); + sidebar: any; + overlay: any; + refinements: any; + estimated_results: any; + player_overlays: any; + playability_status: { + status: number; + error_screen: any; + embeddable: boolean; + reason: string; + }; + streaming_data: { + expires: Date; + formats: import("../parser/contents/classes/Format")[]; + adaptive_formats: import("../parser/contents/classes/Format")[]; + dash_manifest_url: any; + dls_manifest_url: any; + }; + captions: any; + video_details: import("../parser/contents/classes/VideoDetails"); + annotations: any; + storyboards: any; + endscreen: import("../parser/contents/classes/Endscreen"); + cards: import("../parser/contents/classes/CardCollection"); + }; + #private; +} diff --git a/typings/lib/core/VideoItem.d.ts b/typings/lib/core/VideoItem.d.ts new file mode 100644 index 000000000..a85841125 --- /dev/null +++ b/typings/lib/core/VideoItem.d.ts @@ -0,0 +1,43 @@ +export = SimpleVideo; +/** + * Wraps around: + * - Video + * - GridVideo + * - CompactVideo + * - PlaylistVideo + * - PlaylistPanelVideo + * - TODO: WatchCardCompactVideo + * + * Provides a unified interface for all of them. + * + * TODO: refactor - name this VideoItem + */ +declare class SimpleVideo { + static get regex(): RegExp; + constructor(video: any); + getUnderlyingRenderer(): import("../parser/contents/Video") | import("../parser/contents/GridVideo") | import("../parser/contents/CompactVideo") | import("../parser/contents/PlaylistVideo") | import("../parser/contents/PlaylistPanelVideo"); + get id(): any; + get title(): string; + get description(): any; + get channel(): import("../parser/contents/Author"); + get metadata(): { + view_count: any; + short_view_count_text: { + simple_text: any; + accessibility_label: string; + }; + thumbnail: import("../parser/contents/Thumbnail"); + thumbnails: import("../parser/contents/Thumbnail")[]; + moving_thumbnail: any; + moving_thumbnails: any; + published: any; + duration: { + seconds: number; + simple_text: string; + accessibility_label: string; + }; + badges: any; + owner_badges: string[]; + }; + #private; +} diff --git a/typings/lib/parser/contents/Author.d.ts b/typings/lib/parser/contents/Author.d.ts new file mode 100644 index 000000000..7b245d82e --- /dev/null +++ b/typings/lib/parser/contents/Author.d.ts @@ -0,0 +1,31 @@ +export = Author; +declare class Author { + constructor(item: any, badges: any, thumbs: any); + /** + * @type {import('./MetadataBadge')[]} + */ + badges: import('./MetadataBadge')[]; + /** + * @type {Thumbnail[]} + */ + thumbnails: Thumbnail[]; + get url(): any; + set name(arg: string); + get name(): string; + get endpoint(): import("./NavigationEndpoint"); + get id(): any; + /** + * @type {boolean} + */ + get is_verified(): boolean; + /** + * @type {boolean} + */ + get is_verified_artist(): boolean; + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail(): Thumbnail; + #private; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/BackstageImage.d.ts b/typings/lib/parser/contents/BackstageImage.d.ts new file mode 100644 index 000000000..3c4f60437 --- /dev/null +++ b/typings/lib/parser/contents/BackstageImage.d.ts @@ -0,0 +1,7 @@ +export = BackstageImage; +declare class BackstageImage { + constructor(item: any); + type: string; + image: Thumbnail[]; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/BackstagePost.d.ts b/typings/lib/parser/contents/BackstagePost.d.ts new file mode 100644 index 000000000..3961a86ed --- /dev/null +++ b/typings/lib/parser/contents/BackstagePost.d.ts @@ -0,0 +1,15 @@ +export = BackstagePost; +declare class BackstagePost { + constructor(item: any); + type: string; + id: any; + author: Author; + content: Text; + published_at: Text; + likes: Text; + actions: any; + attachment: any; + get endpoint(): any; +} +import Author = require("./Author"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/BackstagePostThread.d.ts b/typings/lib/parser/contents/BackstagePostThread.d.ts new file mode 100644 index 000000000..73d48fd10 --- /dev/null +++ b/typings/lib/parser/contents/BackstagePostThread.d.ts @@ -0,0 +1,6 @@ +export = BackstagePostThread; +declare class BackstagePostThread { + constructor(item: any); + type: string; + post: any; +} diff --git a/typings/lib/parser/contents/Boilerplate.d.ts b/typings/lib/parser/contents/Boilerplate.d.ts new file mode 100644 index 000000000..544786a5e --- /dev/null +++ b/typings/lib/parser/contents/Boilerplate.d.ts @@ -0,0 +1,5 @@ +export = MetadataBadge; +declare class MetadataBadge { + constructor(item: any); + type: string; +} diff --git a/typings/lib/parser/contents/Button.d.ts b/typings/lib/parser/contents/Button.d.ts new file mode 100644 index 000000000..dca64690c --- /dev/null +++ b/typings/lib/parser/contents/Button.d.ts @@ -0,0 +1,15 @@ +export = Button; +declare class Button { + constructor(item: any); + type: string; + navigation_endpoint: NavigationEndpoint; + service_endpoint: NavigationEndpoint; + text: Text; + tooltip: any; + icon: { + icon_type: any; + }; + get endpoint(): NavigationEndpoint; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/C4TabbedHeader.d.ts b/typings/lib/parser/contents/C4TabbedHeader.d.ts new file mode 100644 index 000000000..515a8027f --- /dev/null +++ b/typings/lib/parser/contents/C4TabbedHeader.d.ts @@ -0,0 +1,16 @@ +export = C4TabbedHeader; +declare class C4TabbedHeader { + constructor(item: any); + type: string; + author: Author; + banner: Thumbnail[]; + tv_banner: Thumbnail[]; + mobile_banner: Thumbnail[]; + subscribers: Text; + sponsor_button: any; + subscribe_button: any; + header_links: any; +} +import Author = require("./Author"); +import Thumbnail = require("./Thumbnail"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/Channel.d.ts b/typings/lib/parser/contents/Channel.d.ts new file mode 100644 index 000000000..9f6480e3b --- /dev/null +++ b/typings/lib/parser/contents/Channel.d.ts @@ -0,0 +1,14 @@ +export = Channel; +declare class Channel { + constructor(item: any); + type: string; + id: any; + author: Author; + subscribers: Text; + videos: Text; + endpoint: NavigationEndpoint; + description_snippet: Text; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ChannelAboutFullMetadata.d.ts b/typings/lib/parser/contents/ChannelAboutFullMetadata.d.ts new file mode 100644 index 000000000..5612738c5 --- /dev/null +++ b/typings/lib/parser/contents/ChannelAboutFullMetadata.d.ts @@ -0,0 +1,17 @@ +export = ChannelAboutFullMetadata; +declare class ChannelAboutFullMetadata { + constructor(item: any); + type: string; + id: any; + canonical_channel_url: any; + author: Author; + views: Text; + joined: Text; + description: Text; + email_reveal: NavigationEndpoint; + can_reveal_email: boolean; + country: Text; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ChannelHeaderLinks.d.ts b/typings/lib/parser/contents/ChannelHeaderLinks.d.ts new file mode 100644 index 000000000..3203982eb --- /dev/null +++ b/typings/lib/parser/contents/ChannelHeaderLinks.d.ts @@ -0,0 +1,7 @@ +export = ChannelHeaderLinks; +declare class ChannelHeaderLinks { + constructor(item: any); + type: string; + primary: any; + secondary: any; +} diff --git a/typings/lib/parser/contents/ChannelMetadata.d.ts b/typings/lib/parser/contents/ChannelMetadata.d.ts new file mode 100644 index 000000000..1de6ad2dd --- /dev/null +++ b/typings/lib/parser/contents/ChannelMetadata.d.ts @@ -0,0 +1,19 @@ +export = ChannelMetadata; +declare class ChannelMetadata { + constructor(item: any); + type: string; + title: any; + description: any; + url: any; + rss_urls: any; + vanity_channel_url: any; + external_id: any; + is_family_safe: any; + keywords: any; + avatar: Thumbnail[]; + available_countries: any; + android_deep_link: any; + android_appindexing_link: any; + ios_appindexing_link: any; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/ChannelVideoPlayer.d.ts b/typings/lib/parser/contents/ChannelVideoPlayer.d.ts new file mode 100644 index 000000000..0d60556a5 --- /dev/null +++ b/typings/lib/parser/contents/ChannelVideoPlayer.d.ts @@ -0,0 +1,11 @@ +export = ChannelVideoPlayer; +declare class ChannelVideoPlayer { + constructor(item: any); + type: string; + id: any; + title: Text; + description: Text; + views: Text; + published_at: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/ChildVideo.d.ts b/typings/lib/parser/contents/ChildVideo.d.ts new file mode 100644 index 000000000..8f7ad9f20 --- /dev/null +++ b/typings/lib/parser/contents/ChildVideo.d.ts @@ -0,0 +1,11 @@ +export = ChildVideo; +declare class ChildVideo { + constructor(item: any); + type: string; + id: any; + title: Text; + length: Text; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ChipCloudChip.d.ts b/typings/lib/parser/contents/ChipCloudChip.d.ts new file mode 100644 index 000000000..45b1c1a1a --- /dev/null +++ b/typings/lib/parser/contents/ChipCloudChip.d.ts @@ -0,0 +1,10 @@ +export = ChipCloudChip; +declare class ChipCloudChip { + constructor(item: any); + type: string; + selected: any; + endpoint: NavigationEndpoint; + text: Text; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/CollageHeroImage.d.ts b/typings/lib/parser/contents/CollageHeroImage.d.ts new file mode 100644 index 000000000..8dc0a5b7c --- /dev/null +++ b/typings/lib/parser/contents/CollageHeroImage.d.ts @@ -0,0 +1,11 @@ +export = CollageHeroImage; +declare class CollageHeroImage { + constructor(item: any); + type: string; + left: Thumbnail[]; + top_right: Thumbnail[]; + bottom_right: Thumbnail[]; + endpoint: NavigationEndpoint; +} +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/CommentActionButtons.d.ts b/typings/lib/parser/contents/CommentActionButtons.d.ts new file mode 100644 index 000000000..b35cd0623 --- /dev/null +++ b/typings/lib/parser/contents/CommentActionButtons.d.ts @@ -0,0 +1,8 @@ +export = CommentActionButtons; +declare class CommentActionButtons { + constructor(item: any); + type: string; + like: any; + reply: any; + dislike: any; +} diff --git a/typings/lib/parser/contents/CompactVideo.d.ts b/typings/lib/parser/contents/CompactVideo.d.ts new file mode 100644 index 000000000..3784c1b84 --- /dev/null +++ b/typings/lib/parser/contents/CompactVideo.d.ts @@ -0,0 +1,19 @@ +export = CompactVideo; +declare class CompactVideo { + constructor(item: any); + type: string; + id: any; + thumbnails: Thumbnail[]; + rich_thumbnail: any; + title: Text; + author: Author; + published_at: Text; + views: Text; + duration: Text; + endpoint: NavigationEndpoint; + get best_thumbnail(): Thumbnail; +} +import Thumbnail = require("./Thumbnail"); +import Text = require("./Text"); +import Author = require("./Author"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ContinuationItem.d.ts b/typings/lib/parser/contents/ContinuationItem.d.ts new file mode 100644 index 000000000..7daac7f95 --- /dev/null +++ b/typings/lib/parser/contents/ContinuationItem.d.ts @@ -0,0 +1,45 @@ +export = ContinuationItem; +declare class ContinuationItem { + constructor(item: any); + type: string; + is_resolved: boolean; + is_rejected: boolean; + pending_promise: any; + endpoint: NavigationEndpoint; + call(session: any): Promise; + response: { + contents: any; + on_response_received_actions: any; + on_response_received_endpoints: any; + on_response_received_commands: any; + continuation_contents: any; + metadata: any; + header: any; + microformat: import("./classes/PlayerMicroformat"); + sidebar: any; + overlay: any; + refinements: any; + estimated_results: any; + player_overlays: any; + playability_status: { + status: number; + error_screen: any; + embeddable: boolean; + reason: string; + }; + streaming_data: { + expires: Date; + formats: import("./classes/Format")[]; + adaptive_formats: import("./classes/Format")[]; + dash_manifest_url: any; + dls_manifest_url: any; + }; + captions: any; + video_details: import("./classes/VideoDetails"); + annotations: any; + storyboards: any; + endscreen: import("./classes/Endscreen"); + cards: import("./classes/CardCollection"); + }; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ExpandableTab.d.ts b/typings/lib/parser/contents/ExpandableTab.d.ts new file mode 100644 index 000000000..3b9f0acf0 --- /dev/null +++ b/typings/lib/parser/contents/ExpandableTab.d.ts @@ -0,0 +1,10 @@ +export = ExpandableTab; +declare class ExpandableTab { + constructor(item: any); + type: string; + title: any; + endpoint: NavigationEndpoint; + selected: any; + content: any; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/Format.d.ts b/typings/lib/parser/contents/Format.d.ts new file mode 100644 index 000000000..a1d50a37e --- /dev/null +++ b/typings/lib/parser/contents/Format.d.ts @@ -0,0 +1,35 @@ +export = Format; +declare class Format { + constructor(item: any); + itag: any; + mime_type: any; + bitrate: any; + width: any; + height: any; + last_modified: Date; + content_length: number; + quality: any; + fps: any; + quality_label: any; + projection_type: any; + average_bitrate: any; + audio_bitrate: any; + audio_quality: any; + approx_duration_ms: number; + audio_sample_rate: number; + audio_channels: any; + signature_cipher: any; + cipher: any; + _url: any; + init_range: { + start: number; + end: number; + }; + index_range: { + start: number; + end: number; + }; + get has_audio(): boolean; + get has_video(): boolean; + getDecipheredUrl(session: any): string; +} diff --git a/typings/lib/parser/contents/GenericContainer.d.ts b/typings/lib/parser/contents/GenericContainer.d.ts new file mode 100644 index 000000000..a39851514 --- /dev/null +++ b/typings/lib/parser/contents/GenericContainer.d.ts @@ -0,0 +1,7 @@ +declare function _exports(name: any): { + new (item: any): { + type: any; + content: any; + }; +}; +export = _exports; diff --git a/typings/lib/parser/contents/GenericList.d.ts b/typings/lib/parser/contents/GenericList.d.ts new file mode 100644 index 000000000..cbd243401 --- /dev/null +++ b/typings/lib/parser/contents/GenericList.d.ts @@ -0,0 +1,8 @@ +declare function _exports(name: any, field?: string): { + new (items: any): { + type: any; + is_list: boolean; + contents: any; + }; +}; +export = _exports; diff --git a/typings/lib/parser/contents/GridChannel.d.ts b/typings/lib/parser/contents/GridChannel.d.ts new file mode 100644 index 000000000..fe681ef81 --- /dev/null +++ b/typings/lib/parser/contents/GridChannel.d.ts @@ -0,0 +1,13 @@ +export = GridChannel; +declare class GridChannel { + constructor(item: any); + type: string; + id: any; + author: Author; + subscribers: Text; + videos: Text; + endpoint: NavigationEndpoint; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/GridPlaylist.d.ts b/typings/lib/parser/contents/GridPlaylist.d.ts new file mode 100644 index 000000000..a5f77b8c0 --- /dev/null +++ b/typings/lib/parser/contents/GridPlaylist.d.ts @@ -0,0 +1,16 @@ +export = GridPlaylist; +declare class GridPlaylist { + constructor(item: any); + type: string; + id: any; + videos: Text; + thumbnails: Thumbnail[]; + video_thumbnails: any; + title: Text; + endpoint: NavigationEndpoint; + view_playlist: NavigatableText; +} +import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import NavigatableText = require("./NavigatableText"); diff --git a/typings/lib/parser/contents/GridVideo.d.ts b/typings/lib/parser/contents/GridVideo.d.ts new file mode 100644 index 000000000..242be15db --- /dev/null +++ b/typings/lib/parser/contents/GridVideo.d.ts @@ -0,0 +1,21 @@ +export = GridVideo; +declare class GridVideo { + constructor(item: any); + type: string; + id: any; + author: Author; + thumbnails: Thumbnail[]; + rich_thumbnail: any; + title: Text; + badges: any; + duration: string | Text; + published_at: Text; + views: Text; + endpoint: NavigationEndpoint; + short_view_count: Text; + get best_thumbnail(): Thumbnail; +} +import Author = require("./Author"); +import Thumbnail = require("./Thumbnail"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/HorizontalCardList.d.ts b/typings/lib/parser/contents/HorizontalCardList.d.ts new file mode 100644 index 000000000..28133bfc4 --- /dev/null +++ b/typings/lib/parser/contents/HorizontalCardList.d.ts @@ -0,0 +1,8 @@ +export = HorizontalCardList; +declare class HorizontalCardList { + constructor(item: any); + type: string; + cards: any; + header: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/HorizontalList.d.ts b/typings/lib/parser/contents/HorizontalList.d.ts new file mode 100644 index 000000000..55d2d069a --- /dev/null +++ b/typings/lib/parser/contents/HorizontalList.d.ts @@ -0,0 +1,7 @@ +export = HorizontalList; +declare class HorizontalList { + constructor(item: any); + type: string; + visible_item_count: any; + items: any; +} diff --git a/typings/lib/parser/contents/Menu.d.ts b/typings/lib/parser/contents/Menu.d.ts new file mode 100644 index 000000000..64084acd1 --- /dev/null +++ b/typings/lib/parser/contents/Menu.d.ts @@ -0,0 +1,7 @@ +export = Menu; +declare class Menu { + constructor(item: any); + type: string; + top_level_buttons: any; + items: any; +} diff --git a/typings/lib/parser/contents/MenuNavigationItem.d.ts b/typings/lib/parser/contents/MenuNavigationItem.d.ts new file mode 100644 index 000000000..223a748f5 --- /dev/null +++ b/typings/lib/parser/contents/MenuNavigationItem.d.ts @@ -0,0 +1,9 @@ +export = MenuNavigationItem; +declare class MenuNavigationItem { + constructor(item: any); + type: string; + endpoint: NavigationEndpoint; + text: Text; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/MenuServiceItem.d.ts b/typings/lib/parser/contents/MenuServiceItem.d.ts new file mode 100644 index 000000000..09028d2a8 --- /dev/null +++ b/typings/lib/parser/contents/MenuServiceItem.d.ts @@ -0,0 +1,9 @@ +export = MenuServiceItem; +declare class MenuServiceItem { + constructor(item: any); + type: string; + endpoint: NavigationEndpoint; + text: Text; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/MetadataBadge.d.ts b/typings/lib/parser/contents/MetadataBadge.d.ts new file mode 100644 index 000000000..7b69f3c6d --- /dev/null +++ b/typings/lib/parser/contents/MetadataBadge.d.ts @@ -0,0 +1,13 @@ +export = MetadataBadge; +declare class MetadataBadge { + constructor(item: any); + type: string; + style: any; + label: any; + non_abbreviated_label: any; + /** + * Get label as string + * @returns {string} + */ + toString(): string; +} diff --git a/typings/lib/parser/contents/MetadataRow.d.ts b/typings/lib/parser/contents/MetadataRow.d.ts new file mode 100644 index 000000000..abc7cb602 --- /dev/null +++ b/typings/lib/parser/contents/MetadataRow.d.ts @@ -0,0 +1,8 @@ +export = MetadataRow; +declare class MetadataRow { + constructor(item: any); + type: string; + contents: any; + title: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/MetadataRowContainer.d.ts b/typings/lib/parser/contents/MetadataRowContainer.d.ts new file mode 100644 index 000000000..a174caea3 --- /dev/null +++ b/typings/lib/parser/contents/MetadataRowContainer.d.ts @@ -0,0 +1,6 @@ +export = MetadataRowContainer; +declare class MetadataRowContainer { + constructor(item: any); + type: string; + rows: any; +} diff --git a/typings/lib/parser/contents/MetadataRowHeader.d.ts b/typings/lib/parser/contents/MetadataRowHeader.d.ts new file mode 100644 index 000000000..6d0b79564 --- /dev/null +++ b/typings/lib/parser/contents/MetadataRowHeader.d.ts @@ -0,0 +1,8 @@ +export = MetadataRowHeader; +declare class MetadataRowHeader { + constructor(item: any); + type: string; + text: Text; + has_divider_line: any; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/MicroformatData.d.ts b/typings/lib/parser/contents/MicroformatData.d.ts new file mode 100644 index 000000000..48f80448a --- /dev/null +++ b/typings/lib/parser/contents/MicroformatData.d.ts @@ -0,0 +1,29 @@ +export = MicroformatData; +declare class MicroformatData { + constructor(item: any); + type: string; + url_canonical: any; + title: any; + description: any; + thumbnail: Thumbnail[]; + site_name: any; + app_name: any; + android_package: any; + ios_app_store_id: any; + ios_app_arguments: any; + og_type: any; + url_applinks_web: any; + url_applinks_ios: any; + url_applinks_android: any; + url_twitter_ios: any; + url_twitter_android: any; + twitter_card_type: any; + twitter_site_handle: any; + schema_dot_org_type: any; + noindex: any; + is_unlisted: any; + is_family_safe: any; + tags: any; + available_countries: any; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/Mix.d.ts b/typings/lib/parser/contents/Mix.d.ts new file mode 100644 index 000000000..2a1c96536 --- /dev/null +++ b/typings/lib/parser/contents/Mix.d.ts @@ -0,0 +1,6 @@ +export = Mix; +declare class Mix extends Playlist { + thumbnail: Thumbnail[]; +} +import Playlist = require("./Playlist"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/MovingThumbnail.d.ts b/typings/lib/parser/contents/MovingThumbnail.d.ts new file mode 100644 index 000000000..61b32dd6d --- /dev/null +++ b/typings/lib/parser/contents/MovingThumbnail.d.ts @@ -0,0 +1,7 @@ +export = MovingThumbnail; +declare class MovingThumbnail { + constructor(item: any); + type: string; + thumbnails: Thumbnail[]; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/NavigatableText.d.ts b/typings/lib/parser/contents/NavigatableText.d.ts new file mode 100644 index 000000000..a5bedb5ad --- /dev/null +++ b/typings/lib/parser/contents/NavigatableText.d.ts @@ -0,0 +1,8 @@ +export = NavigatableText; +declare class NavigatableText extends Text { + constructor(node: any); + endpoint: NavigationEndpoint; + toJSON(): NavigatableText; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/NavigationEndpoint.d.ts b/typings/lib/parser/contents/NavigationEndpoint.d.ts new file mode 100644 index 000000000..05349ff1b --- /dev/null +++ b/typings/lib/parser/contents/NavigationEndpoint.d.ts @@ -0,0 +1,62 @@ +/// +export = NavigationEndpoint; +declare class NavigationEndpoint { + constructor(item: any); + type: string; + metadata: { + api_url: any; + url: any; + send_post: any; + page_type: any; + }; + browse: { + browseId: any; + params: any; + base_url: any; + }; + watchVideo: { + video_id: any; + playlist_id: any; + index: any; + params: any; + }; + search: { + query: any; + params: any; + }; + watchPlaylist: any; + watchReel: { + video_id: any; + player_params: any; + params: any; + sequence_provider: any; + sequence_params: any; + }; + url: { + url: import("url").URL; + target: any; + nofollow: any; + }; + continuation: { + request: any; + token: any; + trigger: any; + }; + is_reveal_business_emal: boolean; + sign_in: { + next: NavigationEndpoint; + }; + modal: { + title: any; + button: any; + content: any; + }; + perform_comment_action: {}; + /** + * + * @param {import('../../Innertube')} session + * @returns + */ + call(session: import('../../Innertube')): Actions.Response; +} +import Actions = require("../../core/Actions"); diff --git a/typings/lib/parser/contents/PlayerStoryboardSpec.d.ts b/typings/lib/parser/contents/PlayerStoryboardSpec.d.ts new file mode 100644 index 000000000..3d7141536 --- /dev/null +++ b/typings/lib/parser/contents/PlayerStoryboardSpec.d.ts @@ -0,0 +1,11 @@ +export = PlayerStoryboardSpec; +/** + * This is taken directly from node-ytdl-core + * which is under the same MIT license as this library. + * @see https://github.com/fent/node-ytdl-core/blob/11103be3ab373551bddd0938bc0bbaea033acb8e/lib/info-extras.js#L297 + */ +declare class PlayerStoryboardSpec { + constructor(item: any); + type: string; + boards: any; +} diff --git a/typings/lib/parser/contents/Playlist.d.ts b/typings/lib/parser/contents/Playlist.d.ts new file mode 100644 index 000000000..e251e7b9e --- /dev/null +++ b/typings/lib/parser/contents/Playlist.d.ts @@ -0,0 +1,17 @@ +export = Playlist; +declare class Playlist { + constructor(item: any); + type: string; + id: any; + title: Text; + author: Author; + thumbnails: any; + videos: number; + first_videos: any; + endpoint: NavigationEndpoint; + view_playlist: NavigatableText; +} +import Text = require("./Text"); +import Author = require("./Author"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import NavigatableText = require("./NavigatableText"); diff --git a/typings/lib/parser/contents/PlaylistMetadata.d.ts b/typings/lib/parser/contents/PlaylistMetadata.d.ts new file mode 100644 index 000000000..9e86ce1a6 --- /dev/null +++ b/typings/lib/parser/contents/PlaylistMetadata.d.ts @@ -0,0 +1,7 @@ +export = PlaylistMetadata; +declare class PlaylistMetadata { + constructor(item: any); + type: string; + title: any; + description: any; +} diff --git a/typings/lib/parser/contents/PlaylistPanelVideo.d.ts b/typings/lib/parser/contents/PlaylistPanelVideo.d.ts new file mode 100644 index 000000000..af830e88c --- /dev/null +++ b/typings/lib/parser/contents/PlaylistPanelVideo.d.ts @@ -0,0 +1,18 @@ +export = PlaylistPanelVideo; +declare class PlaylistPanelVideo { + constructor(item: any); + type: string; + index: string; + selected: any; + duration: Text; + author: Author; + endpoint: NavigationEndpoint; + thumbnails: Thumbnail[]; + title: Text; + id: any; + get best_thumbnail(): Thumbnail; +} +import Text = require("./Text"); +import Author = require("./Author"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/PlaylistSidebarPrimaryInfo.d.ts b/typings/lib/parser/contents/PlaylistSidebarPrimaryInfo.d.ts new file mode 100644 index 000000000..a9e46708e --- /dev/null +++ b/typings/lib/parser/contents/PlaylistSidebarPrimaryInfo.d.ts @@ -0,0 +1,13 @@ +export = PlaylistSidebarPrimaryInfo; +declare class PlaylistSidebarPrimaryInfo { + constructor(item: any); + type: string; + stats: any; + thumbnail_renderer: any; + title: Text; + menu: any; + endpoint: NavigationEndpoint; + description: Text; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/PlaylistSidebarSecondaryInfo.d.ts b/typings/lib/parser/contents/PlaylistSidebarSecondaryInfo.d.ts new file mode 100644 index 000000000..2c15bef91 --- /dev/null +++ b/typings/lib/parser/contents/PlaylistSidebarSecondaryInfo.d.ts @@ -0,0 +1,7 @@ +export = PlaylistSidebarSecondaryInfo; +declare class PlaylistSidebarSecondaryInfo { + constructor(item: any); + type: string; + owner: any; + button: any; +} diff --git a/typings/lib/parser/contents/PlaylistVideo.d.ts b/typings/lib/parser/contents/PlaylistVideo.d.ts new file mode 100644 index 000000000..a561f0c83 --- /dev/null +++ b/typings/lib/parser/contents/PlaylistVideo.d.ts @@ -0,0 +1,18 @@ +export = PlaylistVideo; +declare class PlaylistVideo { + constructor(item: any); + type: string; + index: string; + is_playable: any; + duration: Text; + endpoint: NavigationEndpoint; + author: Author; + thumbnails: Thumbnail[]; + title: Text; + id: any; + get best_thumbnail(): Thumbnail; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import Author = require("./Author"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/PlaylistVideoList.d.ts b/typings/lib/parser/contents/PlaylistVideoList.d.ts new file mode 100644 index 000000000..5adbed9b9 --- /dev/null +++ b/typings/lib/parser/contents/PlaylistVideoList.d.ts @@ -0,0 +1,9 @@ +export = PlaylistVideoList; +declare class PlaylistVideoList { + constructor(item: any); + type: string; + is_editable: any; + can_reorder: any; + id: any; + contents: any; +} diff --git a/typings/lib/parser/contents/PlaylistVideoThumbnail.d.ts b/typings/lib/parser/contents/PlaylistVideoThumbnail.d.ts new file mode 100644 index 000000000..20297c3ef --- /dev/null +++ b/typings/lib/parser/contents/PlaylistVideoThumbnail.d.ts @@ -0,0 +1,7 @@ +export = PlaylistVideoThumbnail; +declare class PlaylistVideoThumbnail { + constructor(item: any); + type: string; + thumbnail: Thumbnail[]; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/ReelItem.d.ts b/typings/lib/parser/contents/ReelItem.d.ts new file mode 100644 index 000000000..1f22cf71f --- /dev/null +++ b/typings/lib/parser/contents/ReelItem.d.ts @@ -0,0 +1,13 @@ +export = ReelItem; +declare class ReelItem { + constructor(item: any); + type: string; + id: any; + title: Text; + thumbnails: Thumbnail[]; + views: Text; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/ReelShelf.d.ts b/typings/lib/parser/contents/ReelShelf.d.ts new file mode 100644 index 000000000..2ca786058 --- /dev/null +++ b/typings/lib/parser/contents/ReelShelf.d.ts @@ -0,0 +1,10 @@ +export = ReelShelf; +declare class ReelShelf { + constructor(item: any); + type: string; + title: Text; + items: any; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/RichGrid.d.ts b/typings/lib/parser/contents/RichGrid.d.ts new file mode 100644 index 000000000..1e1f2351f --- /dev/null +++ b/typings/lib/parser/contents/RichGrid.d.ts @@ -0,0 +1,7 @@ +export = RichGrid; +declare class RichGrid { + constructor(item: any); + type: string; + header: any; + contents: any; +} diff --git a/typings/lib/parser/contents/RichShelf.d.ts b/typings/lib/parser/contents/RichShelf.d.ts new file mode 100644 index 000000000..a6e330ad9 --- /dev/null +++ b/typings/lib/parser/contents/RichShelf.d.ts @@ -0,0 +1,10 @@ +export = RichShelf; +declare class RichShelf { + constructor(item: any); + type: string; + title: Text; + contents: any; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/SearchRefinementCard.d.ts b/typings/lib/parser/contents/SearchRefinementCard.d.ts new file mode 100644 index 000000000..138b0b202 --- /dev/null +++ b/typings/lib/parser/contents/SearchRefinementCard.d.ts @@ -0,0 +1,12 @@ +export = SearchRefinementCard; +declare class SearchRefinementCard { + constructor(item: any); + type: string; + thumbnail: Thumbnail[]; + endpoint: NavigationEndpoint; + query: Text; + style: any; +} +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/Shelf.d.ts b/typings/lib/parser/contents/Shelf.d.ts new file mode 100644 index 000000000..e163e9767 --- /dev/null +++ b/typings/lib/parser/contents/Shelf.d.ts @@ -0,0 +1,11 @@ +export = Shelf; +declare class Shelf { + constructor(item: any); + type: string; + title: Text; + content: any; + endpoint: NavigationEndpoint; + button: any; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/Tab.d.ts b/typings/lib/parser/contents/Tab.d.ts new file mode 100644 index 000000000..5a0462be8 --- /dev/null +++ b/typings/lib/parser/contents/Tab.d.ts @@ -0,0 +1,13 @@ +export = Tab; +declare class Tab { + constructor(item: any); + type: string; + /** + * @type {string} + */ + title: string; + endpoint: NavigationEndpoint; + selected: any; + content: any; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/Text.d.ts b/typings/lib/parser/contents/Text.d.ts new file mode 100644 index 000000000..a8f6291ff --- /dev/null +++ b/typings/lib/parser/contents/Text.d.ts @@ -0,0 +1,20 @@ +export = Text; +declare class Text { + constructor(txt: any, def?: any); + type: string; + /** + * @type {string | undefined} + */ + text: string | undefined; + runs: any; + /** + * Get the string representation of this text + * @note may return an empty string if this.text is undefined + * @returns {string} + */ + toString(): string; + toJSON(): { + string: string; + runs: any; + }; +} diff --git a/typings/lib/parser/contents/TextRun.d.ts b/typings/lib/parser/contents/TextRun.d.ts new file mode 100644 index 000000000..94b207a85 --- /dev/null +++ b/typings/lib/parser/contents/TextRun.d.ts @@ -0,0 +1,8 @@ +export = TextRun; +declare class TextRun { + constructor(node: any); + type: string; + text: any; + endpoint: NavigationEndpoint; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/Thumbnail.d.ts b/typings/lib/parser/contents/Thumbnail.d.ts new file mode 100644 index 000000000..bf3346ced --- /dev/null +++ b/typings/lib/parser/contents/Thumbnail.d.ts @@ -0,0 +1,26 @@ +export = Thumbnail; +declare class Thumbnail { + /** + * Get thumbnails from response object + * @param {*} response response object + * @returns {Thumbnail[]} sorted array of thumbnails + */ + static fromResponse({ thumbnails }: any): Thumbnail[]; + constructor({ url, width, height }: { + url: any; + width: any; + height: any; + }); + /** + * @type {string} + */ + url: string; + /** + * @type {number} + */ + width: number; + /** + * @type {number} + */ + height: number; +} diff --git a/typings/lib/parser/contents/ToggleButton.d.ts b/typings/lib/parser/contents/ToggleButton.d.ts new file mode 100644 index 000000000..ab57186a7 --- /dev/null +++ b/typings/lib/parser/contents/ToggleButton.d.ts @@ -0,0 +1,19 @@ +export = ToggleButton; +declare class ToggleButton { + constructor(item: any); + type: string; + is_toggled: any; + is_disabled: any; + default_service_endpoint: NavigationEndpoint; + toggled_service_endpoint: NavigationEndpoint; + default_navigation_endpoint: NavigationEndpoint; + default_tooltip: any; + toggled_tooltip: any; + default_text: Text; + toggled_text: Text; + get endpoint(): NavigationEndpoint; + get tooltip(): any; + get text(): Text; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/TwoColumnBrowseResults.d.ts b/typings/lib/parser/contents/TwoColumnBrowseResults.d.ts new file mode 100644 index 000000000..c5a0409ad --- /dev/null +++ b/typings/lib/parser/contents/TwoColumnBrowseResults.d.ts @@ -0,0 +1,6 @@ +export = TwoColumnBrowseResults; +declare class TwoColumnBrowseResults { + constructor(item: any); + type: string; + tabs: any; +} diff --git a/typings/lib/parser/contents/TwoColumnSearchResults.d.ts b/typings/lib/parser/contents/TwoColumnSearchResults.d.ts new file mode 100644 index 000000000..9906bd4b1 --- /dev/null +++ b/typings/lib/parser/contents/TwoColumnSearchResults.d.ts @@ -0,0 +1,7 @@ +export = TwoColumnSearchResults; +declare class TwoColumnSearchResults { + constructor(items: any); + type: string; + primary: any; + secondary: any; +} diff --git a/typings/lib/parser/contents/TwoColumnWatchNextResults.d.ts b/typings/lib/parser/contents/TwoColumnWatchNextResults.d.ts new file mode 100644 index 000000000..9b7d60983 --- /dev/null +++ b/typings/lib/parser/contents/TwoColumnWatchNextResults.d.ts @@ -0,0 +1,21 @@ +export = TwoColumnWatchNextResult; +declare class TwoColumnWatchNextResult { + constructor(item: any); + type: string; + primary: any; + secondary: any; + playlist: { + current_index: any; + endpoint: NavigationEndpoint; + is_course: any; + is_infinite: any; + author: Author; + save: any; + title: NavigatableText; + videos: any; + contents: any; + }; +} +import NavigationEndpoint = require("./NavigationEndpoint"); +import Author = require("./Author"); +import NavigatableText = require("./NavigatableText"); diff --git a/typings/lib/parser/contents/UniversalWatchCard.d.ts b/typings/lib/parser/contents/UniversalWatchCard.d.ts new file mode 100644 index 000000000..6b630283c --- /dev/null +++ b/typings/lib/parser/contents/UniversalWatchCard.d.ts @@ -0,0 +1,8 @@ +export = UniversalWatchCard; +declare class UniversalWatchCard { + constructor(items: any); + type: string; + header: any; + hero: any; + sections: any; +} diff --git a/typings/lib/parser/contents/VerticalList.d.ts b/typings/lib/parser/contents/VerticalList.d.ts new file mode 100644 index 000000000..1501d47e7 --- /dev/null +++ b/typings/lib/parser/contents/VerticalList.d.ts @@ -0,0 +1,7 @@ +export = VerticalList; +declare class VerticalList { + constructor(item: any); + type: string; + collapsed_item_count: any; + items: any; +} diff --git a/typings/lib/parser/contents/Video.d.ts b/typings/lib/parser/contents/Video.d.ts new file mode 100644 index 000000000..40f2a3d66 --- /dev/null +++ b/typings/lib/parser/contents/Video.d.ts @@ -0,0 +1,88 @@ +export = Video; +declare class Video { + constructor(item: any); + type: string; + author: Author; + /** + * @type {import('./MetadataBadge')[]} + */ + badges: import('./MetadataBadge')[]; + /** + * @type {Thumbnail[]} + */ + thumbnails: Thumbnail[]; + /** + * @type {import('./MovingThumbnail') | undefined} + */ + rich_thumbnail: import('./MovingThumbnail') | undefined; + /** + * @type {Date | undefined} + */ + upcoming: Date | undefined; + /** + * @type {string} + */ + id: string; + /** + * @type {Text} + */ + title: Text; + /** + * @type {string} + */ + duration: string; + /** + * @type {Text} + */ + published_at: Text; + /** + * @type {Text} + */ + views: Text; + /** + * @type {{ + * text: Text, + * hoverText: Text, + * }[]} + */ + snippets: { + text: Text; + hoverText: Text; + }[]; + /** + * @type {Text} + */ + description_snippet: Text; + /** + * @type {Text} + */ + short_view_count: Text; + /** + * @type {NavigationEndpoint} + */ + endpoint: NavigationEndpoint; + /** + * @returns {string} + */ + get description(): string; + /** + * @type {boolean} + */ + get is_live(): boolean; + /** + * @type {boolean} + */ + get is_upcoming(): boolean; + /** + * @type {boolean} + */ + get has_captions(): boolean; + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail(): Thumbnail; +} +import Author = require("./Author"); +import Thumbnail = require("./Thumbnail"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/VideoDetails.d.ts b/typings/lib/parser/contents/VideoDetails.d.ts new file mode 100644 index 000000000..af5fcb8f8 --- /dev/null +++ b/typings/lib/parser/contents/VideoDetails.d.ts @@ -0,0 +1,37 @@ +export = VideoDetails; +declare class VideoDetails { + constructor(item: any); + /** + * @type {string} + */ + id: string; + /** + * @type {string} + */ + channel_id: string; + /** + * @type {string} + */ + title: string; + /** + * @type {string[]} + */ + keywords: string[]; + /** + * @type {string} + */ + short_description: string; + /** + * @type {string} + */ + author: string; + duration: number; + is_owner_viewing: boolean; + thumbnail: Thumbnail[]; + allow_ratings: boolean; + view_count: number; + is_private: boolean; + is_live_content: boolean; + is_crawlable: boolean; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/VideoOwner.d.ts b/typings/lib/parser/contents/VideoOwner.d.ts new file mode 100644 index 000000000..663335c05 --- /dev/null +++ b/typings/lib/parser/contents/VideoOwner.d.ts @@ -0,0 +1,7 @@ +export = VideoOwner; +declare class VideoOwner { + constructor(item: any); + type: string; + author: Author; +} +import Author = require("./Author"); diff --git a/typings/lib/parser/contents/VideoPrimaryInfo.d.ts b/typings/lib/parser/contents/VideoPrimaryInfo.d.ts new file mode 100644 index 000000000..d022643a5 --- /dev/null +++ b/typings/lib/parser/contents/VideoPrimaryInfo.d.ts @@ -0,0 +1,10 @@ +export = VideoPrimaryInfo; +declare class VideoPrimaryInfo { + constructor(item: any); + type: string; + title: Text; + published_at: Date; + actions: any; + views: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/VideoSecondaryInfo.d.ts b/typings/lib/parser/contents/VideoSecondaryInfo.d.ts new file mode 100644 index 000000000..a942a33a2 --- /dev/null +++ b/typings/lib/parser/contents/VideoSecondaryInfo.d.ts @@ -0,0 +1,10 @@ +export = VideoSecondaryInfo; +declare class VideoSecondaryInfo { + constructor(item: any); + type: string; + owner: any; + description: Text; + metadata: any; + description_collapsed_lines: any; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/WatchCardCompactVideo.d.ts b/typings/lib/parser/contents/WatchCardCompactVideo.d.ts new file mode 100644 index 000000000..0d92c4821 --- /dev/null +++ b/typings/lib/parser/contents/WatchCardCompactVideo.d.ts @@ -0,0 +1,14 @@ +export = WatchCardCompactVideo; +declare class WatchCardCompactVideo { + constructor(item: any); + type: string; + title: Text; + views: any; + published_at: any; + endpoint: NavigationEndpoint; + duration: Text; + byline: NavigatableText; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); +import NavigatableText = require("./NavigatableText"); diff --git a/typings/lib/parser/contents/WatchCardHeroVideo.d.ts b/typings/lib/parser/contents/WatchCardHeroVideo.d.ts new file mode 100644 index 000000000..211ed8d73 --- /dev/null +++ b/typings/lib/parser/contents/WatchCardHeroVideo.d.ts @@ -0,0 +1,8 @@ +export = WatchCardHeroVideo; +declare class WatchCardHeroVideo { + constructor(item: any); + type: string; + endpoint: NavigationEndpoint; + collage: any; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/WatchCardRichHeader.d.ts b/typings/lib/parser/contents/WatchCardRichHeader.d.ts new file mode 100644 index 000000000..361b87cea --- /dev/null +++ b/typings/lib/parser/contents/WatchCardRichHeader.d.ts @@ -0,0 +1,10 @@ +export = WatchCardRichHeader; +declare class WatchCardRichHeader { + constructor(item: any); + type: string; + title: Text; + subtitle: Text; + author: Author; +} +import Text = require("./Text"); +import Author = require("./Author"); diff --git a/typings/lib/parser/contents/WatchCardSectionSequence.d.ts b/typings/lib/parser/contents/WatchCardSectionSequence.d.ts new file mode 100644 index 000000000..353d574de --- /dev/null +++ b/typings/lib/parser/contents/WatchCardSectionSequence.d.ts @@ -0,0 +1,6 @@ +export = WatchCardSectionSequence; +declare class WatchCardSectionSequence { + constructor(item: any); + type: string; + lists: any; +} diff --git a/typings/lib/parser/contents/classes/Author.d.ts b/typings/lib/parser/contents/classes/Author.d.ts index 57d1b2ee3..2c4d200ce 100644 --- a/typings/lib/parser/contents/classes/Author.d.ts +++ b/typings/lib/parser/contents/classes/Author.d.ts @@ -1,11 +1,31 @@ export = Author; declare class Author { - constructor(data: any); - id: any; - url: string; - name: any; - endpoint: any; - badges: any; - is_verified: any; - is_verified_artist: any; + constructor(item: any, badges: any, thumbs: any); + /** + * @type {import('./MetadataBadge')[]} + */ + badges: import('./MetadataBadge')[]; + /** + * @type {Thumbnail[]} + */ + thumbnails: Thumbnail[]; + get url(): any; + set name(arg: any); + get name(): any; + get endpoint(): import("./NavigationEndpoint"); + get id(): any; + /** + * @type {boolean} + */ + get is_verified(): boolean; + /** + * @type {boolean} + */ + get is_verified_artist(): boolean; + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail(): Thumbnail; + #private; } +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/BackstageImage.d.ts b/typings/lib/parser/contents/classes/BackstageImage.d.ts new file mode 100644 index 000000000..1a8ad1039 --- /dev/null +++ b/typings/lib/parser/contents/classes/BackstageImage.d.ts @@ -0,0 +1,7 @@ +export = BackstageImage; +declare class BackstageImage { + constructor(data: any); + type: string; + image: Thumbnail[]; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/BackstagePost.d.ts b/typings/lib/parser/contents/classes/BackstagePost.d.ts new file mode 100644 index 000000000..733a9d450 --- /dev/null +++ b/typings/lib/parser/contents/classes/BackstagePost.d.ts @@ -0,0 +1,15 @@ +export = BackstagePost; +declare class BackstagePost { + constructor(data: any); + type: string; + id: any; + author: Author; + content: Text; + published_at: Text; + likes: Text; + actions: any; + attachment: any; + get endpoint(): any; +} +import Author = require("./Author"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/BackstagePostThread.d.ts b/typings/lib/parser/contents/classes/BackstagePostThread.d.ts new file mode 100644 index 000000000..c4687c929 --- /dev/null +++ b/typings/lib/parser/contents/classes/BackstagePostThread.d.ts @@ -0,0 +1,6 @@ +export = BackstagePostThread; +declare class BackstagePostThread { + constructor(data: any); + type: string; + post: any; +} diff --git a/typings/lib/parser/contents/classes/C4TabbedHeader.d.ts b/typings/lib/parser/contents/classes/C4TabbedHeader.d.ts new file mode 100644 index 000000000..75ebd7f28 --- /dev/null +++ b/typings/lib/parser/contents/classes/C4TabbedHeader.d.ts @@ -0,0 +1,16 @@ +export = C4TabbedHeader; +declare class C4TabbedHeader { + constructor(data: any); + type: string; + author: Author; + banner: Thumbnail[]; + tv_banner: Thumbnail[]; + mobile_banner: Thumbnail[]; + subscribers: Text; + sponsor_button: any; + subscribe_button: any; + header_links: any; +} +import Author = require("./Author"); +import Thumbnail = require("./Thumbnail"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/CallToActionButton.d.ts b/typings/lib/parser/contents/classes/CallToActionButton.d.ts new file mode 100644 index 000000000..3369fabf8 --- /dev/null +++ b/typings/lib/parser/contents/classes/CallToActionButton.d.ts @@ -0,0 +1,9 @@ +export = CallToActionButton; +declare class CallToActionButton { + constructor(data: any); + type: string; + label: Text; + icon_type: any; + style: any; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/Channel.d.ts b/typings/lib/parser/contents/classes/Channel.d.ts new file mode 100644 index 000000000..a28cfa705 --- /dev/null +++ b/typings/lib/parser/contents/classes/Channel.d.ts @@ -0,0 +1,14 @@ +export = Channel; +declare class Channel { + constructor(data: any); + type: string; + id: any; + author: Author; + subscribers: Text; + videos: Text; + endpoint: NavigationEndpoint; + description_snippet: Text; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ChannelAboutFullMetadata.d.ts b/typings/lib/parser/contents/classes/ChannelAboutFullMetadata.d.ts new file mode 100644 index 000000000..eb531559e --- /dev/null +++ b/typings/lib/parser/contents/classes/ChannelAboutFullMetadata.d.ts @@ -0,0 +1,17 @@ +export = ChannelAboutFullMetadata; +declare class ChannelAboutFullMetadata { + constructor(data: any); + type: string; + id: any; + canonical_channel_url: any; + author: Author; + views: Text; + joined: Text; + description: Text; + email_reveal: NavigationEndpoint; + can_reveal_email: boolean; + country: Text; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ChannelHeaderLinks.d.ts b/typings/lib/parser/contents/classes/ChannelHeaderLinks.d.ts new file mode 100644 index 000000000..796138c79 --- /dev/null +++ b/typings/lib/parser/contents/classes/ChannelHeaderLinks.d.ts @@ -0,0 +1,7 @@ +export = ChannelHeaderLinks; +declare class ChannelHeaderLinks { + constructor(data: any); + type: string; + primary: any; + secondary: any; +} diff --git a/typings/lib/parser/contents/classes/ChannelMetadata.d.ts b/typings/lib/parser/contents/classes/ChannelMetadata.d.ts new file mode 100644 index 000000000..bc85fa907 --- /dev/null +++ b/typings/lib/parser/contents/classes/ChannelMetadata.d.ts @@ -0,0 +1,19 @@ +export = ChannelMetadata; +declare class ChannelMetadata { + constructor(data: any); + type: string; + title: any; + description: any; + url: any; + rss_urls: any; + vanity_channel_url: any; + external_id: any; + is_family_safe: any; + keywords: any; + avatar: Thumbnail[]; + available_countries: any; + android_deep_link: any; + android_appindexing_link: any; + ios_appindexing_link: any; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/ChannelThumbnailWithLink.d.ts b/typings/lib/parser/contents/classes/ChannelThumbnailWithLink.d.ts index a89fbc494..c1315f2cc 100644 --- a/typings/lib/parser/contents/classes/ChannelThumbnailWithLink.d.ts +++ b/typings/lib/parser/contents/classes/ChannelThumbnailWithLink.d.ts @@ -2,8 +2,9 @@ export = ChannelThumbnailWithLink; declare class ChannelThumbnailWithLink { constructor(data: any); type: string; - thumbnails: any; + thumbnails: Thumbnail[]; endpoint: NavigationEndpoint; label: any; } +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ChannelVideoPlayer.d.ts b/typings/lib/parser/contents/classes/ChannelVideoPlayer.d.ts new file mode 100644 index 000000000..54214e37c --- /dev/null +++ b/typings/lib/parser/contents/classes/ChannelVideoPlayer.d.ts @@ -0,0 +1,11 @@ +export = ChannelVideoPlayer; +declare class ChannelVideoPlayer { + constructor(data: any); + type: string; + id: any; + title: Text; + description: Text; + views: Text; + published_at: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/ChipCloudChip.d.ts b/typings/lib/parser/contents/classes/ChipCloudChip.d.ts index 70304f7c6..bb96b6a6e 100644 --- a/typings/lib/parser/contents/classes/ChipCloudChip.d.ts +++ b/typings/lib/parser/contents/classes/ChipCloudChip.d.ts @@ -2,8 +2,9 @@ export = ChipCloudChip; declare class ChipCloudChip { constructor(data: any); type: string; - text: any; - endpoint: NavigationEndpoint; is_selected: any; + endpoint: NavigationEndpoint; + text: Text; } import NavigationEndpoint = require("./NavigationEndpoint"); +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/CollageHeroImage.d.ts b/typings/lib/parser/contents/classes/CollageHeroImage.d.ts new file mode 100644 index 000000000..9ab61092b --- /dev/null +++ b/typings/lib/parser/contents/classes/CollageHeroImage.d.ts @@ -0,0 +1,11 @@ +export = CollageHeroImage; +declare class CollageHeroImage { + constructor(data: any); + type: string; + left: Thumbnail[]; + top_right: Thumbnail[]; + bottom_right: Thumbnail[]; + endpoint: NavigationEndpoint; +} +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/CommentActionButtons.d.ts b/typings/lib/parser/contents/classes/CommentActionButtons.d.ts new file mode 100644 index 000000000..4ddc3936f --- /dev/null +++ b/typings/lib/parser/contents/classes/CommentActionButtons.d.ts @@ -0,0 +1,8 @@ +export = CommentActionButtons; +declare class CommentActionButtons { + constructor(data: any); + type: string; + like: any; + reply: any; + dislike: any; +} diff --git a/typings/lib/parser/contents/classes/CommentsEntryPointHeader.d.ts b/typings/lib/parser/contents/classes/CommentsEntryPointHeader.d.ts index 93aa4b472..3fb9accff 100644 --- a/typings/lib/parser/contents/classes/CommentsEntryPointHeader.d.ts +++ b/typings/lib/parser/contents/classes/CommentsEntryPointHeader.d.ts @@ -4,8 +4,9 @@ declare class CommentsEntryPointHeader { type: string; header: Text; comment_count: Text; - teaser_avatar: any; + teaser_avatar: Thumbnail[]; teaser_content: Text; simplebox_placeholder: Text; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/CompactVideo.d.ts b/typings/lib/parser/contents/classes/CompactVideo.d.ts index dfd5902d7..bbb778726 100644 --- a/typings/lib/parser/contents/classes/CompactVideo.d.ts +++ b/typings/lib/parser/contents/classes/CompactVideo.d.ts @@ -3,6 +3,8 @@ declare class CompactVideo { constructor(data: any); type: string; id: any; + thumbnails: Thumbnail[]; + rich_thumbnail: any; title: Text; author: Author; view_count: Text; @@ -12,12 +14,12 @@ declare class CompactVideo { text: any; seconds: number; }; - thumbnails: any; - channel_thumbnails: any; thumbnail_overlays: any; endpoint: NavigationEndpoint; menu: any; + get best_thumbnail(): Thumbnail; } +import Thumbnail = require("./Thumbnail"); import Text = require("./Text"); import Author = require("./Author"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/EndScreenPlaylist.d.ts b/typings/lib/parser/contents/classes/EndScreenPlaylist.d.ts index b96af6176..32a97f434 100644 --- a/typings/lib/parser/contents/classes/EndScreenPlaylist.d.ts +++ b/typings/lib/parser/contents/classes/EndScreenPlaylist.d.ts @@ -6,8 +6,9 @@ declare class EndScreenPlaylist { title: Text; author: Text; endpoint: NavigationEndpoint; - thumbnails: any; + thumbnails: Thumbnail[]; video_count: Text; } import Text = require("./Text"); import NavigationEndpoint = require("./NavigationEndpoint"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/EndScreenVideo.d.ts b/typings/lib/parser/contents/classes/EndScreenVideo.d.ts index 0841d3a85..9e8eae2ab 100644 --- a/typings/lib/parser/contents/classes/EndScreenVideo.d.ts +++ b/typings/lib/parser/contents/classes/EndScreenVideo.d.ts @@ -4,7 +4,7 @@ declare class EndScreenVideo { type: string; id: any; title: Text; - thumbnails: any; + thumbnails: Thumbnail[]; thumbnail_overlays: any; author: Author; endpoint: NavigationEndpoint; @@ -15,5 +15,6 @@ declare class EndScreenVideo { }; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import Author = require("./Author"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/EndscreenElement.d.ts b/typings/lib/parser/contents/classes/EndscreenElement.d.ts index e68410682..1e59df12b 100644 --- a/typings/lib/parser/contents/classes/EndscreenElement.d.ts +++ b/typings/lib/parser/contents/classes/EndscreenElement.d.ts @@ -3,8 +3,8 @@ declare class EndscreenElement { constructor(data: any); type: string; style: any; - image: any; - icon: any; + image: Thumbnail[]; + icon: Thumbnail[]; metadata: Text; call_to_action: Text; hovercard_button: any; @@ -20,5 +20,6 @@ declare class EndscreenElement { end_ms: any; id: any; } +import Thumbnail = require("./Thumbnail"); import Text = require("./Text"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ExpandableTab.d.ts b/typings/lib/parser/contents/classes/ExpandableTab.d.ts new file mode 100644 index 000000000..bef052371 --- /dev/null +++ b/typings/lib/parser/contents/classes/ExpandableTab.d.ts @@ -0,0 +1,10 @@ +export = ExpandableTab; +declare class ExpandableTab { + constructor(data: any); + type: string; + title: any; + endpoint: NavigationEndpoint; + selected: any; + content: any; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ExpandedShelfContents.d.ts b/typings/lib/parser/contents/classes/ExpandedShelfContents.d.ts new file mode 100644 index 000000000..35cdc4df0 --- /dev/null +++ b/typings/lib/parser/contents/classes/ExpandedShelfContents.d.ts @@ -0,0 +1,7 @@ +export = ExpandedShelfContents; +declare class ExpandedShelfContents { + constructor(data: any); + type: string; + items: any; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/FeedFilterChipBar.d.ts b/typings/lib/parser/contents/classes/FeedFilterChipBar.d.ts new file mode 100644 index 000000000..9db2e9ecd --- /dev/null +++ b/typings/lib/parser/contents/classes/FeedFilterChipBar.d.ts @@ -0,0 +1,6 @@ +export = FeedFilterChipBar; +declare class FeedFilterChipBar { + constructor(data: any); + type: string; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/Format.d.ts b/typings/lib/parser/contents/classes/Format.d.ts index 4d48b9554..40bfa9313 100644 --- a/typings/lib/parser/contents/classes/Format.d.ts +++ b/typings/lib/parser/contents/classes/Format.d.ts @@ -7,10 +7,16 @@ declare class Format { average_bitrate: any; width: any; height: any; - init_range: any; - index_range: any; - last_modified: any; - content_length: any; + init_range: { + start: number; + end: number; + }; + index_range: { + start: number; + end: number; + }; + last_modified: Date; + content_length: number; quality: any; quality_label: any; fps: any; @@ -18,7 +24,8 @@ declare class Format { cipher: any; signature_cipher: any; audio_quality: any; - approx_duration_ms: any; + approx_duration_ms: number; + audio_sample_rate: number; audio_channels: any; loudness_db: any; has_audio: boolean; diff --git a/typings/lib/parser/contents/classes/Grid.d.ts b/typings/lib/parser/contents/classes/Grid.d.ts index 404de820d..215cec3cc 100644 --- a/typings/lib/parser/contents/classes/Grid.d.ts +++ b/typings/lib/parser/contents/classes/Grid.d.ts @@ -3,6 +3,7 @@ declare class Grid { constructor(data: any); type: string; items: any; + contents: any; is_collapsible: any; visible_row_count: any; target_id: any; diff --git a/typings/lib/parser/contents/classes/GridChannel.d.ts b/typings/lib/parser/contents/classes/GridChannel.d.ts new file mode 100644 index 000000000..5bae5a112 --- /dev/null +++ b/typings/lib/parser/contents/classes/GridChannel.d.ts @@ -0,0 +1,13 @@ +export = GridChannel; +declare class GridChannel { + constructor(data: any); + type: string; + id: any; + author: Author; + subscribers: Text; + videos: Text; + endpoint: NavigationEndpoint; +} +import Author = require("./Author"); +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/GridPlaylist.d.ts b/typings/lib/parser/contents/classes/GridPlaylist.d.ts index 26a80f84c..2309b3d87 100644 --- a/typings/lib/parser/contents/classes/GridPlaylist.d.ts +++ b/typings/lib/parser/contents/classes/GridPlaylist.d.ts @@ -7,7 +7,8 @@ declare class GridPlaylist { author: PlaylistAuthor; badges: any; endpoint: NavigationEndpoint; - thumbnails: any; + view_playlist: NavigatableText; + thumbnails: Thumbnail[]; sidebar_thumbnails: any[]; video_count: Text; video_count_short_text: Text; @@ -15,3 +16,5 @@ declare class GridPlaylist { import Text = require("./Text"); import PlaylistAuthor = require("./PlaylistAuthor"); import NavigationEndpoint = require("./NavigationEndpoint"); +import NavigatableText = require("./NavigatableText"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/GridVideo.d.ts b/typings/lib/parser/contents/classes/GridVideo.d.ts index 1906600e1..8e5abb7eb 100644 --- a/typings/lib/parser/contents/classes/GridVideo.d.ts +++ b/typings/lib/parser/contents/classes/GridVideo.d.ts @@ -4,8 +4,9 @@ declare class GridVideo { type: string; id: any; title: Text; - thumbnails: any; + thumbnails: Thumbnail[]; thumbnail_overlays: any; + rich_thumbnail: any; published: Text; duration: string | Text; author: Author; @@ -15,5 +16,6 @@ declare class GridVideo { menu: any; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import Author = require("./Author"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/HorizontalList.d.ts b/typings/lib/parser/contents/classes/HorizontalList.d.ts new file mode 100644 index 000000000..addc3c68b --- /dev/null +++ b/typings/lib/parser/contents/classes/HorizontalList.d.ts @@ -0,0 +1,8 @@ +export = HorizontalList; +declare class HorizontalList { + constructor(data: any); + type: string; + visible_item_count: any; + items: any; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/Menu.d.ts b/typings/lib/parser/contents/classes/Menu.d.ts index bd5098958..be0dbf587 100644 --- a/typings/lib/parser/contents/classes/Menu.d.ts +++ b/typings/lib/parser/contents/classes/Menu.d.ts @@ -3,6 +3,7 @@ declare class Menu { constructor(data: any); type: string; items: any; + contents: any; top_level_buttons: any; label: any; } diff --git a/typings/lib/parser/contents/classes/MenuServiceItemDownload.d.ts b/typings/lib/parser/contents/classes/MenuServiceItemDownload.d.ts new file mode 100644 index 000000000..92342f3c1 --- /dev/null +++ b/typings/lib/parser/contents/classes/MenuServiceItemDownload.d.ts @@ -0,0 +1,8 @@ +export = MenuServiceItemDownload; +declare class MenuServiceItemDownload { + constructor(data: any); + type: string; + has_separator: any; + endpoint: NavigationEndpoint; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/MerchandiseItem.d.ts b/typings/lib/parser/contents/classes/MerchandiseItem.d.ts index 0ba9a0322..79fe62b2f 100644 --- a/typings/lib/parser/contents/classes/MerchandiseItem.d.ts +++ b/typings/lib/parser/contents/classes/MerchandiseItem.d.ts @@ -4,7 +4,7 @@ declare class MerchandiseItem { type: string; title: any; description: any; - thumbnails: any; + thumbnails: Thumbnail[]; price: any; vendor_name: any; button_text: any; @@ -14,4 +14,5 @@ declare class MerchandiseItem { region_format: any; endpoint: NavigationEndpoint; } +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/MerchandiseShelf.d.ts b/typings/lib/parser/contents/classes/MerchandiseShelf.d.ts index 4376ff7fb..b0646e913 100644 --- a/typings/lib/parser/contents/classes/MerchandiseShelf.d.ts +++ b/typings/lib/parser/contents/classes/MerchandiseShelf.d.ts @@ -5,4 +5,5 @@ declare class MerchandiseShelf { title: any; menu: any; items: any; + contents: any; } diff --git a/typings/lib/parser/contents/classes/MicroformatData.d.ts b/typings/lib/parser/contents/classes/MicroformatData.d.ts new file mode 100644 index 000000000..54bd85989 --- /dev/null +++ b/typings/lib/parser/contents/classes/MicroformatData.d.ts @@ -0,0 +1,29 @@ +export = MicroformatData; +declare class MicroformatData { + constructor(data: any); + type: string; + url_canonical: any; + title: any; + description: any; + thumbnail: Thumbnail[]; + site_name: any; + app_name: any; + android_package: any; + ios_app_store_id: any; + ios_app_arguments: any; + og_type: any; + url_applinks_web: any; + url_applinks_ios: any; + url_applinks_android: any; + url_twitter_ios: any; + url_twitter_android: any; + twitter_card_type: any; + twitter_site_handle: any; + schema_dot_org_type: any; + noindex: any; + is_unlisted: any; + is_family_safe: any; + tags: any; + available_countries: any; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.d.ts b/typings/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.d.ts index cc82bbabf..4dac74d45 100644 --- a/typings/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.d.ts +++ b/typings/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.d.ts @@ -4,5 +4,6 @@ declare class MusicCarouselShelfBasicHeader { type: string; strapline: any; title: any; - thumbnail: any; + thumbnail: Thumbnail[]; } +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/MusicResponsiveListItem.d.ts b/typings/lib/parser/contents/classes/MusicResponsiveListItem.d.ts index 0e6974f6f..3617f316f 100644 --- a/typings/lib/parser/contents/classes/MusicResponsiveListItem.d.ts +++ b/typings/lib/parser/contents/classes/MusicResponsiveListItem.d.ts @@ -3,7 +3,7 @@ declare class MusicResponsiveListItem { constructor(data: any); type: string; endpoint: NavigationEndpoint; - thumbnails: any; + thumbnails: Thumbnail[]; badges: any; menu: any; overlay: any; @@ -12,9 +12,6 @@ declare class MusicResponsiveListItem { duration: { text: any; seconds: number; - } | { - text: any; - seconds: number; }; album: { id: any; @@ -27,14 +24,6 @@ declare class MusicResponsiveListItem { name: any; channel_id: any; endpoint: any; - } | { - name: any; - channel_id: any; - endpoint: any; - } | { - name: any; - channel_id: any; - endpoint: any; }; name: any; subscribers: any; @@ -43,3 +32,4 @@ declare class MusicResponsiveListItem { #private; } import NavigationEndpoint = require("./NavigationEndpoint"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/MusicTwoRowItem.d.ts b/typings/lib/parser/contents/classes/MusicTwoRowItem.d.ts index e4116e6fb..962064d4c 100644 --- a/typings/lib/parser/contents/classes/MusicTwoRowItem.d.ts +++ b/typings/lib/parser/contents/classes/MusicTwoRowItem.d.ts @@ -22,9 +22,10 @@ declare class MusicTwoRowItem { endpoint: any; }; artists: any; - thumbnail: any; + thumbnail: Thumbnail[]; thumbnail_overlay: any; menu: any; } import Text = require("./Text"); import NavigationEndpoint = require("./NavigationEndpoint"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/NavigatableText.d.ts b/typings/lib/parser/contents/classes/NavigatableText.d.ts new file mode 100644 index 000000000..2402c9119 --- /dev/null +++ b/typings/lib/parser/contents/classes/NavigatableText.d.ts @@ -0,0 +1,8 @@ +export = NavigatableText; +declare class NavigatableText extends Text { + type: string; + endpoint: NavigationEndpoint; + toJSON(): NavigatableText; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlayerAnnotationsExpanded.d.ts b/typings/lib/parser/contents/classes/PlayerAnnotationsExpanded.d.ts index a061980d7..dd67c2134 100644 --- a/typings/lib/parser/contents/classes/PlayerAnnotationsExpanded.d.ts +++ b/typings/lib/parser/contents/classes/PlayerAnnotationsExpanded.d.ts @@ -5,7 +5,7 @@ declare class PlayerAnnotationsExpanded { featured_channel: { start_time_ms: any; end_time_ms: any; - watermark: any; + watermark: Thumbnail[]; channel_name: any; endpoint: NavigationEndpoint; subscribe_button: any; @@ -13,4 +13,5 @@ declare class PlayerAnnotationsExpanded { allow_swipe_dismiss: any; annotation_id: any; } +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlayerErrorMessage.d.ts b/typings/lib/parser/contents/classes/PlayerErrorMessage.d.ts index b319a20f8..01bddf658 100644 --- a/typings/lib/parser/contents/classes/PlayerErrorMessage.d.ts +++ b/typings/lib/parser/contents/classes/PlayerErrorMessage.d.ts @@ -5,7 +5,8 @@ declare class PlayerErrorMessage { subreason: Text; reason: Text; proceed_button: any; - thumbnails: any; + thumbnails: Thumbnail[]; icon_type: any; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/PlayerMicroformat.d.ts b/typings/lib/parser/contents/classes/PlayerMicroformat.d.ts index 433d8edbe..d8d4d86a2 100644 --- a/typings/lib/parser/contents/classes/PlayerMicroformat.d.ts +++ b/typings/lib/parser/contents/classes/PlayerMicroformat.d.ts @@ -4,7 +4,7 @@ declare class PlayerMicroformat { type: string; title: Text; description: Text; - thumbnails: any; + thumbnails: Thumbnail[]; embed: { iframe_url: any; flash_url: any; @@ -28,3 +28,4 @@ declare class PlayerMicroformat { available_countries: any; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/PlayerOverlayAutoplay.d.ts b/typings/lib/parser/contents/classes/PlayerOverlayAutoplay.d.ts index 66ab442bc..0ea4d11c7 100644 --- a/typings/lib/parser/contents/classes/PlayerOverlayAutoplay.d.ts +++ b/typings/lib/parser/contents/classes/PlayerOverlayAutoplay.d.ts @@ -9,7 +9,7 @@ declare class PlayerOverlayAutoplay { prefer_immediate_redirect: any; count_down_secs_for_fullscreen: any; published: Text; - background: any; + background: Thumbnail[]; thumbnail_overlays: any; author: Author; cancel_button: any; @@ -17,4 +17,5 @@ declare class PlayerOverlayAutoplay { close_button: any; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import Author = require("./Author"); diff --git a/typings/lib/parser/contents/classes/Playlist.d.ts b/typings/lib/parser/contents/classes/Playlist.d.ts index cc755ce47..c66005222 100644 --- a/typings/lib/parser/contents/classes/Playlist.d.ts +++ b/typings/lib/parser/contents/classes/Playlist.d.ts @@ -5,7 +5,7 @@ declare class Playlist { id: any; title: Text; author: Text | PlaylistAuthor; - thumbnails: any; + thumbnails: Thumbnail[]; video_count: Text; video_count_short: Text; first_videos: any; @@ -17,4 +17,5 @@ declare class Playlist { } import Text = require("./Text"); import PlaylistAuthor = require("./PlaylistAuthor"); +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlaylistAuthor.d.ts b/typings/lib/parser/contents/classes/PlaylistAuthor.d.ts index 286f97735..d854ac8cc 100644 --- a/typings/lib/parser/contents/classes/PlaylistAuthor.d.ts +++ b/typings/lib/parser/contents/classes/PlaylistAuthor.d.ts @@ -1,4 +1,5 @@ export = PlaylistAuthor; declare class PlaylistAuthor extends Author { + constructor(data: any); } import Author = require("./Author"); diff --git a/typings/lib/parser/contents/classes/PlaylistMetadata.d.ts b/typings/lib/parser/contents/classes/PlaylistMetadata.d.ts new file mode 100644 index 000000000..6e826672f --- /dev/null +++ b/typings/lib/parser/contents/classes/PlaylistMetadata.d.ts @@ -0,0 +1,7 @@ +export = PlaylistMetadata; +declare class PlaylistMetadata { + constructor(data: any); + type: string; + title: any; + description: any; +} diff --git a/typings/lib/parser/contents/classes/PlaylistPanelVideo.d.ts b/typings/lib/parser/contents/classes/PlaylistPanelVideo.d.ts index 32a304565..8cfb633a7 100644 --- a/typings/lib/parser/contents/classes/PlaylistPanelVideo.d.ts +++ b/typings/lib/parser/contents/classes/PlaylistPanelVideo.d.ts @@ -3,7 +3,7 @@ declare class PlaylistPanelVideo { constructor(data: any); type: string; title: Text; - thumbnail: any; + thumbnail: Thumbnail[]; endpoint: NavigationEndpoint; selected: any; video_id: any; @@ -24,4 +24,5 @@ declare class PlaylistPanelVideo { set_video_id: any; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlaylistSidebar.d.ts b/typings/lib/parser/contents/classes/PlaylistSidebar.d.ts new file mode 100644 index 000000000..52e2281a8 --- /dev/null +++ b/typings/lib/parser/contents/classes/PlaylistSidebar.d.ts @@ -0,0 +1,7 @@ +export = PlaylistSidebar; +declare class PlaylistSidebar { + constructor(data: any); + type: string; + items: any; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.d.ts b/typings/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.d.ts new file mode 100644 index 000000000..1d850226d --- /dev/null +++ b/typings/lib/parser/contents/classes/PlaylistSidebarPrimaryInfo.d.ts @@ -0,0 +1,13 @@ +export = PlaylistSidebarPrimaryInfo; +declare class PlaylistSidebarPrimaryInfo { + constructor(data: any); + type: string; + stats: any; + thumbnail_renderer: any; + title: Text; + menu: any; + endpoint: NavigationEndpoint; + description: Text; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.d.ts b/typings/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.d.ts new file mode 100644 index 000000000..1d6341424 --- /dev/null +++ b/typings/lib/parser/contents/classes/PlaylistSidebarSecondaryInfo.d.ts @@ -0,0 +1,7 @@ +export = PlaylistSidebarSecondaryInfo; +declare class PlaylistSidebarSecondaryInfo { + constructor(data: any); + type: string; + owner: any; + button: any; +} diff --git a/typings/lib/parser/contents/classes/PlaylistVideo.d.ts b/typings/lib/parser/contents/classes/PlaylistVideo.d.ts index 22f14bb68..b75402221 100644 --- a/typings/lib/parser/contents/classes/PlaylistVideo.d.ts +++ b/typings/lib/parser/contents/classes/PlaylistVideo.d.ts @@ -6,7 +6,7 @@ declare class PlaylistVideo { index: Text; title: Text; author: PlaylistAuthor; - thumbnails: any; + thumbnails: Thumbnail[]; set_video_id: any; endpoint: NavigationEndpoint; is_playable: any; @@ -17,4 +17,5 @@ declare class PlaylistVideo { } import Text = require("./Text"); import PlaylistAuthor = require("./PlaylistAuthor"); +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/PlaylistVideoThumbnail.d.ts b/typings/lib/parser/contents/classes/PlaylistVideoThumbnail.d.ts new file mode 100644 index 000000000..d63e358be --- /dev/null +++ b/typings/lib/parser/contents/classes/PlaylistVideoThumbnail.d.ts @@ -0,0 +1,7 @@ +export = PlaylistVideoThumbnail; +declare class PlaylistVideoThumbnail { + constructor(data: any); + type: string; + thumbnail: Thumbnail[]; +} +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/ProfileColumn.d.ts b/typings/lib/parser/contents/classes/ProfileColumn.d.ts index 746b6f775..195303087 100644 --- a/typings/lib/parser/contents/classes/ProfileColumn.d.ts +++ b/typings/lib/parser/contents/classes/ProfileColumn.d.ts @@ -3,4 +3,5 @@ declare class ProfileColumn { constructor(data: any); type: string; items: any; + contents: any; } diff --git a/typings/lib/parser/contents/classes/ProfileColumnStats.d.ts b/typings/lib/parser/contents/classes/ProfileColumnStats.d.ts index 3098a4755..980b94081 100644 --- a/typings/lib/parser/contents/classes/ProfileColumnStats.d.ts +++ b/typings/lib/parser/contents/classes/ProfileColumnStats.d.ts @@ -3,4 +3,5 @@ declare class ProfileColumnStats { constructor(data: any); type: string; items: any; + contents: any; } diff --git a/typings/lib/parser/contents/classes/ProfileColumnUserInfo.d.ts b/typings/lib/parser/contents/classes/ProfileColumnUserInfo.d.ts index 9b1ea82cc..faeb08734 100644 --- a/typings/lib/parser/contents/classes/ProfileColumnUserInfo.d.ts +++ b/typings/lib/parser/contents/classes/ProfileColumnUserInfo.d.ts @@ -3,6 +3,7 @@ declare class ProfileColumnUserInfo { constructor(data: any); type: string; title: Text; - thumbnails: any; + thumbnails: Thumbnail[]; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/ReelItem.d.ts b/typings/lib/parser/contents/classes/ReelItem.d.ts new file mode 100644 index 000000000..ba47a0af6 --- /dev/null +++ b/typings/lib/parser/contents/classes/ReelItem.d.ts @@ -0,0 +1,13 @@ +export = ReelItem; +declare class ReelItem { + constructor(data: any); + type: string; + id: any; + title: Text; + thumbnails: Thumbnail[]; + views: Text; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/ReelShelf.d.ts b/typings/lib/parser/contents/classes/ReelShelf.d.ts new file mode 100644 index 000000000..6a79da9a6 --- /dev/null +++ b/typings/lib/parser/contents/classes/ReelShelf.d.ts @@ -0,0 +1,11 @@ +export = ReelShelf; +declare class ReelShelf { + constructor(data: any); + type: string; + title: Text; + items: any; + endpoint: NavigationEndpoint; + contents: any; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/RichGrid.d.ts b/typings/lib/parser/contents/classes/RichGrid.d.ts new file mode 100644 index 000000000..2c6fc1af7 --- /dev/null +++ b/typings/lib/parser/contents/classes/RichGrid.d.ts @@ -0,0 +1,7 @@ +export = RichGrid; +declare class RichGrid { + constructor(data: any); + type: string; + header: any; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/RichItem.d.ts b/typings/lib/parser/contents/classes/RichItem.d.ts new file mode 100644 index 000000000..fe5249c4a --- /dev/null +++ b/typings/lib/parser/contents/classes/RichItem.d.ts @@ -0,0 +1,6 @@ +export = RichItem; +declare class RichItem { + constructor(data: any); + type: string; + content: any; +} diff --git a/typings/lib/parser/contents/classes/RichSection.d.ts b/typings/lib/parser/contents/classes/RichSection.d.ts new file mode 100644 index 000000000..70afe20d8 --- /dev/null +++ b/typings/lib/parser/contents/classes/RichSection.d.ts @@ -0,0 +1,6 @@ +export = RichSection; +declare class RichSection { + constructor(data: any); + type: string; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/RichShelf.d.ts b/typings/lib/parser/contents/classes/RichShelf.d.ts new file mode 100644 index 000000000..6de96c7f5 --- /dev/null +++ b/typings/lib/parser/contents/classes/RichShelf.d.ts @@ -0,0 +1,10 @@ +export = RichShelf; +declare class RichShelf { + constructor(data: any); + type: string; + title: Text; + contents: any; + endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/SearchRefinementCard.d.ts b/typings/lib/parser/contents/classes/SearchRefinementCard.d.ts index 881111e2f..d007def12 100644 --- a/typings/lib/parser/contents/classes/SearchRefinementCard.d.ts +++ b/typings/lib/parser/contents/classes/SearchRefinementCard.d.ts @@ -2,8 +2,9 @@ export = SearchRefinementCard; declare class SearchRefinementCard { constructor(data: any); type: string; - thumbnails: any; + thumbnails: Thumbnail[]; endpoint: NavigationEndpoint; query: any; } +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/SecondarySearchContainer.d.ts b/typings/lib/parser/contents/classes/SecondarySearchContainer.d.ts new file mode 100644 index 000000000..49a670527 --- /dev/null +++ b/typings/lib/parser/contents/classes/SecondarySearchContainer.d.ts @@ -0,0 +1,6 @@ +export = SecondarySearchContainer; +declare class SecondarySearchContainer { + constructor(data: any); + type: string; + contents: any; +} diff --git a/typings/lib/parser/contents/classes/SingleHeroImage.d.ts b/typings/lib/parser/contents/classes/SingleHeroImage.d.ts new file mode 100644 index 000000000..eb4207529 --- /dev/null +++ b/typings/lib/parser/contents/classes/SingleHeroImage.d.ts @@ -0,0 +1,7 @@ +export = SingleHeroImage; +declare class SingleHeroImage { + constructor(data: any); + type: string; + thumbnails: any; + style: any; +} diff --git a/typings/lib/parser/contents/classes/Thumbnail.d.ts b/typings/lib/parser/contents/classes/Thumbnail.d.ts index 6bbbb93c7..433d3a261 100644 --- a/typings/lib/parser/contents/classes/Thumbnail.d.ts +++ b/typings/lib/parser/contents/classes/Thumbnail.d.ts @@ -1,10 +1,27 @@ export = Thumbnail; declare class Thumbnail { - constructor(data: any); - type: string; - url: any; - width: any; - height: any; - get thumbnails(): any; - #private; + /** + * Get thumbnails from response object + * + * @param {*} response response object + * @returns {Thumbnail[]} sorted array of thumbnails + */ + static fromResponse({ thumbnails }: any): Thumbnail[]; + constructor({ url, width, height }: { + url: any; + width: any; + height: any; + }); + /** + * @type {string} + */ + url: string; + /** + * @type {number} + */ + width: number; + /** + * @type {number} + */ + height: number; } diff --git a/typings/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.d.ts b/typings/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.d.ts new file mode 100644 index 000000000..69603fff9 --- /dev/null +++ b/typings/lib/parser/contents/classes/ThumbnailOverlayLoadingPreview.d.ts @@ -0,0 +1,7 @@ +export = ThumbnailOverlayLoadingPreview; +declare class ThumbnailOverlayLoadingPreview { + constructor(data: any); + type: string; + text: Text; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/UniversalWatchCard.d.ts b/typings/lib/parser/contents/classes/UniversalWatchCard.d.ts new file mode 100644 index 000000000..7a4e1930d --- /dev/null +++ b/typings/lib/parser/contents/classes/UniversalWatchCard.d.ts @@ -0,0 +1,8 @@ +export = UniversalWatchCard; +declare class UniversalWatchCard { + constructor(data: any); + type: string; + header: any; + call_to_action: any; + sections: any; +} diff --git a/typings/lib/parser/contents/classes/VerticalList.d.ts b/typings/lib/parser/contents/classes/VerticalList.d.ts index a95e31777..f15e0e6ef 100644 --- a/typings/lib/parser/contents/classes/VerticalList.d.ts +++ b/typings/lib/parser/contents/classes/VerticalList.d.ts @@ -3,6 +3,7 @@ declare class VerticalList { constructor(data: any); type: string; items: any; + contents: any; collapsed_item_count: any; collapsed_state_button_text: Text; } diff --git a/typings/lib/parser/contents/classes/VerticalWatchCardList.d.ts b/typings/lib/parser/contents/classes/VerticalWatchCardList.d.ts new file mode 100644 index 000000000..fa9b8d2fa --- /dev/null +++ b/typings/lib/parser/contents/classes/VerticalWatchCardList.d.ts @@ -0,0 +1,11 @@ +export = VerticalWatchCardList; +declare class VerticalWatchCardList { + constructor(data: any); + type: string; + items: any; + contents: any; + view_all_text: Text; + view_all_endpoint: NavigationEndpoint; +} +import Text = require("./Text"); +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/Video.d.ts b/typings/lib/parser/contents/classes/Video.d.ts index 952a246c6..d17b10693 100644 --- a/typings/lib/parser/contents/classes/Video.d.ts +++ b/typings/lib/parser/contents/classes/Video.d.ts @@ -4,17 +4,17 @@ declare class Video { type: string; id: any; title: Text; - description: Text; + description_snippet: Text; snippets: any; - thumbnails: any; + thumbnails: Thumbnail[]; thumbnail_overlays: any; - moving_thumbnails: any; - channel_thumbnail: any; + rich_thumbnail: any; author: Author; endpoint: NavigationEndpoint; published: Text; view_count_text: Text; short_view_count_text: Text; + upcoming: Date; duration: { text: any; seconds: number; @@ -22,7 +22,28 @@ declare class Video { show_action_menu: any; is_watched: any; menu: any; + /** + * @returns {string} + */ + get description(): string; + /** + * @type {boolean} + */ + get is_live(): boolean; + /** + * @type {boolean} + */ + get is_upcoming(): boolean; + /** + * @type {boolean} + */ + get has_captions(): boolean; + /** + * @type {Thumbnail | undefined} + */ + get best_thumbnail(): Thumbnail; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import Author = require("./Author"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/VideoDetails.d.ts b/typings/lib/parser/contents/classes/VideoDetails.d.ts index 9a77fa1ca..e32308947 100644 --- a/typings/lib/parser/contents/classes/VideoDetails.d.ts +++ b/typings/lib/parser/contents/classes/VideoDetails.d.ts @@ -1,19 +1,37 @@ export = VideoDetails; declare class VideoDetails { constructor(data: any); - id: any; - title: any; + /** + * @type {string} + */ + id: string; + /** + * @type {string} + */ + channel_id: string; + /** + * @type {string} + */ + title: string; + /** + * @type {string[]} + */ + keywords: string[]; + /** + * @type {string} + */ + short_description: string; + /** + * @type {string} + */ + author: string; duration: number; - keywords: any; - channel_id: any; - is_owner_viewing: any; - description: any; - is_crawlable: any; - thumbnails: any; - allow_ratings: any; + is_owner_viewing: boolean; + thumbnail: Thumbnail[]; + allow_ratings: boolean; view_count: number; - author: any; - is_private: any; - is_unplugged_corpus: any; - is_live_content: any; + is_private: boolean; + is_live_content: boolean; + is_crawlable: boolean; } +import Thumbnail = require("./Thumbnail"); diff --git a/typings/lib/parser/contents/classes/VideoInfoCardContent.d.ts b/typings/lib/parser/contents/classes/VideoInfoCardContent.d.ts index 3189b3317..ec624f84a 100644 --- a/typings/lib/parser/contents/classes/VideoInfoCardContent.d.ts +++ b/typings/lib/parser/contents/classes/VideoInfoCardContent.d.ts @@ -5,9 +5,10 @@ declare class VideoInfoCardContent { title: Text; channel_name: Text; view_count: Text; - video_thumbnails: any; + video_thumbnails: Thumbnail[]; duration: Text; endpoint: NavigationEndpoint; } import Text = require("./Text"); +import Thumbnail = require("./Thumbnail"); import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/VideoOwner.d.ts b/typings/lib/parser/contents/classes/VideoOwner.d.ts index c109267a4..64b8bf547 100644 --- a/typings/lib/parser/contents/classes/VideoOwner.d.ts +++ b/typings/lib/parser/contents/classes/VideoOwner.d.ts @@ -2,14 +2,9 @@ export = VideoOwner; declare class VideoOwner { constructor(data: any); type: string; - name: Text; - thumbnails: any; subscription_button: any; - endpoint: NavigationEndpoint; subscriber_count: Text; - badges: any; - is_verified: any; - is_verified_artist: any; + author: Author; } import Text = require("./Text"); -import NavigationEndpoint = require("./NavigationEndpoint"); +import Author = require("./Author"); diff --git a/typings/lib/parser/contents/classes/WatchCardCompactVideo.d.ts b/typings/lib/parser/contents/classes/WatchCardCompactVideo.d.ts new file mode 100644 index 000000000..b3a7ffb77 --- /dev/null +++ b/typings/lib/parser/contents/classes/WatchCardCompactVideo.d.ts @@ -0,0 +1,13 @@ +export = WatchCardCompactVideo; +declare class WatchCardCompactVideo { + constructor(data: any); + type: string; + title: Text; + subtitle: Text; + duration: { + text: any; + seconds: number; + }; + style: any; +} +import Text = require("./Text"); diff --git a/typings/lib/parser/contents/classes/WatchCardHeroVideo.d.ts b/typings/lib/parser/contents/classes/WatchCardHeroVideo.d.ts new file mode 100644 index 000000000..d7216391d --- /dev/null +++ b/typings/lib/parser/contents/classes/WatchCardHeroVideo.d.ts @@ -0,0 +1,10 @@ +export = WatchCardHeroVideo; +declare class WatchCardHeroVideo { + constructor(data: any); + type: string; + endpoint: NavigationEndpoint; + call_to_action_button: any; + hero_image: any; + label: any; +} +import NavigationEndpoint = require("./NavigationEndpoint"); diff --git a/typings/lib/parser/contents/classes/WatchCardRichHeader.d.ts b/typings/lib/parser/contents/classes/WatchCardRichHeader.d.ts new file mode 100644 index 000000000..79da552c7 --- /dev/null +++ b/typings/lib/parser/contents/classes/WatchCardRichHeader.d.ts @@ -0,0 +1,12 @@ +export = WatchCardRichHeader; +declare class WatchCardRichHeader { + constructor(data: any); + type: string; + title: Text; + title_endpoint: any; + subtitle: Text; + author: Author; + style: any; +} +import Text = require("./Text"); +import Author = require("./Author"); diff --git a/typings/lib/parser/contents/classes/WatchCardSectionSequence.d.ts b/typings/lib/parser/contents/classes/WatchCardSectionSequence.d.ts new file mode 100644 index 000000000..d58df18f0 --- /dev/null +++ b/typings/lib/parser/contents/classes/WatchCardSectionSequence.d.ts @@ -0,0 +1,6 @@ +export = WatchCardSectionSequence; +declare class WatchCardSectionSequence { + constructor(data: any); + type: string; + lists: any; +} diff --git a/typings/lib/parser/contents/index.d.ts b/typings/lib/parser/contents/index.d.ts index 300bafa2d..8b3d7b00d 100644 --- a/typings/lib/parser/contents/index.d.ts +++ b/typings/lib/parser/contents/index.d.ts @@ -1,9 +1,16 @@ export = Parser; declare class Parser { + static "__#9@#memo": Map; + static "__#9@#clearMemo"(): void; + static "__#9@#createMemo"(): void; + static "__#9@#addToMemo"(classname: any, result: any): Map; static parseResponse(data: any): { contents: any; + contents_memo: Map; on_response_received_actions: any; + on_response_received_actions_memo: Map; on_response_received_endpoints: any; + on_response_received_endpoints_memo: Map; on_response_received_commands: any; /** @type {*} */ continuation_contents: any; @@ -43,7 +50,7 @@ declare class Parser { /** @type {import('./classes/CardCollection')} */ cards: import('./classes/CardCollection'); }; - static parseCC(data: any): SectionListContinuation; + static parseLC(data: any): SectionListContinuation; static parseRR(actions: any): any; static parseFormats(formats: any): any; static parse(data: any): any; diff --git a/typings/lib/parser/youtube/Analytics.d.ts b/typings/lib/parser/youtube/Analytics.d.ts index 88ab1dd5d..2ab8ba77c 100644 --- a/typings/lib/parser/youtube/Analytics.d.ts +++ b/typings/lib/parser/youtube/Analytics.d.ts @@ -8,8 +8,11 @@ declare class Analytics { sections: any; get page(): { contents: any; + contents_memo: Map; on_response_received_actions: any; + on_response_received_actions_memo: Map; on_response_received_endpoints: any; + on_response_received_endpoints_memo: Map; on_response_received_commands: any; continuation_contents: any; metadata: any; diff --git a/typings/lib/parser/youtube/Channel.d.ts b/typings/lib/parser/youtube/Channel.d.ts new file mode 100644 index 000000000..c4893b6e3 --- /dev/null +++ b/typings/lib/parser/youtube/Channel.d.ts @@ -0,0 +1,34 @@ +export = Channel; +declare class Channel extends TabbedFeed { + /** + * @type {import('../parser/contents/ChannelMetadata')} + */ + metadata: any; + title: any; + description: any; + getVideos(): Promise; + getPlaylists(): Promise; + getHome(): Promise; + getCommunity(): Promise; + getChannels(): Promise; + /** + * Get the channel about page + * + * @returns {Promise} + */ + getAbout(): Promise; + /** + * @note home_page only returns videos! + * @deprecated use getXXX family of functions instead + */ + get content(): { + home_page: () => never; + getHome: any; + getVideos: any; + getPlaylists: any; + getCommunity: any; + getChannels: any; + getAbout: any; + }; +} +import TabbedFeed = require("../../core/TabbedFeed"); diff --git a/typings/lib/parser/youtube/History.d.ts b/typings/lib/parser/youtube/History.d.ts index b2dcb74f2..1ce277904 100644 --- a/typings/lib/parser/youtube/History.d.ts +++ b/typings/lib/parser/youtube/History.d.ts @@ -5,7 +5,6 @@ declare class History { * @param {object} page - parsed data. * @param {import('../../core/Actions')} actions * @param {boolean} is_continuation - * @function Object() { [native code] } */ constructor(page: object, actions: import('../../core/Actions'), is_continuation: boolean); sections: any; diff --git a/typings/lib/parser/youtube/Library.d.ts b/typings/lib/parser/youtube/Library.d.ts index 644ca20df..00c28b359 100644 --- a/typings/lib/parser/youtube/Library.d.ts +++ b/typings/lib/parser/youtube/Library.d.ts @@ -13,8 +13,11 @@ declare class Library { sections: any; get page(): { contents: any; + contents_memo: Map; on_response_received_actions: any; + on_response_received_actions_memo: Map; on_response_received_endpoints: any; + on_response_received_endpoints_memo: Map; on_response_received_commands: any; continuation_contents: any; metadata: any; diff --git a/typings/lib/parser/youtube/Playlist.d.ts b/typings/lib/parser/youtube/Playlist.d.ts new file mode 100644 index 000000000..dbf910bfd --- /dev/null +++ b/typings/lib/parser/youtube/Playlist.d.ts @@ -0,0 +1,15 @@ +export = Playlist; +declare class Playlist extends Feed { + primary_info: any; + get title(): any; + get description(): any; + get total_items(): any; + get views(): any; + get last_updated(): any; + /** + * @alias videos + */ + get items(): (import("../contents/classes/PlaylistPanelVideo") | import("../contents/classes/CompactVideo") | import("../contents/classes/Video") | import("../contents/classes/GridVideo") | import("../contents/classes/PlaylistVideo") | import("../contents/classes/WatchCardCompactVideo"))[]; + #private; +} +import Feed = require("../../core/Feed"); diff --git a/typings/lib/parser/youtube/Search.d.ts b/typings/lib/parser/youtube/Search.d.ts index 8bbc635a2..664df936c 100644 --- a/typings/lib/parser/youtube/Search.d.ts +++ b/typings/lib/parser/youtube/Search.d.ts @@ -1,25 +1,23 @@ export = Search; /** @namespace */ -declare class Search { +declare class Search extends Feed { /** * @param {object} response - API response. * @param {import('../../core/Actions')} actions - * @param {object} [args] - * @param {boolean} [args.is_continuation] + * @param {object} [already_parsed = false] - already parsed response. */ - constructor(response: object, actions: import('../../core/Actions'), args?: { - is_continuation?: boolean; - }); + constructor(actions: import('../../core/Actions'), data: any, already_parsed?: object); /** @type {object[]} */ results: object[]; refinements: any; estimated_results: any; - /** @type {{ sections: { title: string, items: object[] }[] }} */ - sections: { - sections: { - title: string; - items: object[]; - }[]; + watch_card: { + /** @type {import('../contents/classes/UniversalWatchCard')} */ + header: import('../contents/classes/UniversalWatchCard'); + /** @type {import('../contents/classes/WatchCardHeroVideo')} */ + call_to_action: import('../contents/classes/WatchCardHeroVideo'); + /** @type {import('../contents/classes/WatchCardSectionSequence')[]} */ + sections: import('../contents/classes/WatchCardSectionSequence')[]; }; refinement_cards: { /** @type {import('../contents/classes/RichListHeader')} */ @@ -28,26 +26,13 @@ declare class Search { cards: import('../contents/classes/SearchRefinementCard'); }; /** - * Retrieves next batch of results. - * - * @returns {Promise.} - */ - getContinuation(): Promise; - /** - * Applies given refinement card and returns a new {@link Search} object. + * Applies given refinement card and returns a new {@link Feed} object. * * @param {import('../contents/classes/SearchRefinementCard') | string} card - refinement card object or query - * @returns {Promise.} + * @returns {Promise.} */ - selectRefinementCard(card: import('../contents/classes/SearchRefinementCard') | string): Promise; - /** @type {boolean} */ - get has_continuation(): boolean; + selectRefinementCard(card: import('../contents/classes/SearchRefinementCard') | string): Promise; /** @type {string[]} */ get refinement_card_queries(): string[]; - /** @type {import('../contents/classes/Video')[]} */ - get videos(): import("../contents/classes/Video")[]; - /** @type {import('../contents/classes/Playlist')[]} */ - get playlists(): import("../contents/classes/Playlist")[]; - get page(): any; - #private; } +import Feed = require("../../core/Feed"); diff --git a/typings/lib/parser/youtube/VideoInfo.d.ts b/typings/lib/parser/youtube/VideoInfo.d.ts index a624ec44b..82a659b9f 100644 --- a/typings/lib/parser/youtube/VideoInfo.d.ts +++ b/typings/lib/parser/youtube/VideoInfo.d.ts @@ -123,8 +123,11 @@ declare class VideoInfo { get filters(): string[]; get page(): { contents: any; + contents_memo: Map; on_response_received_actions: any; + on_response_received_actions_memo: Map; on_response_received_endpoints: any; + on_response_received_endpoints_memo: Map; on_response_received_commands: any; continuation_contents: any; metadata: any; @@ -140,7 +143,9 @@ declare class VideoInfo { error_screen: any; embeddable: boolean; reason: string; - }; + }; /** + * @type {import('../contents/classes/CardCollection')} + */ streaming_data: { expires: Date; formats: import("../contents/classes/Format")[]; @@ -155,5 +160,13 @@ declare class VideoInfo { endscreen: import("../contents/classes/Endscreen"); cards: import("../contents/classes/CardCollection"); }[]; + /** + * Get songs used in the video. + * + * @returns {{ [key: string]: import('../parser/contents/Text')[] }[]} + */ + get music_tracks(): { + [key: string]: any[]; + }[]; #private; } diff --git a/typings/lib/parser/ytmusic/Search.d.ts b/typings/lib/parser/ytmusic/Search.d.ts index 678e268b1..bbff322bd 100644 --- a/typings/lib/parser/ytmusic/Search.d.ts +++ b/typings/lib/parser/ytmusic/Search.d.ts @@ -7,7 +7,6 @@ declare class Search { * @param {object} args * @param {boolean} args.is_continuation * @param {boolean} args.is_filtered - * @function Object() { [native code] } */ constructor(response: object, actions: import('../../core/Actions'), args?: { is_continuation: boolean;