feat: migrate all playlist renderers to TypeScript

This commit is contained in:
LuanRT
2022-08-04 01:56:53 -03:00
parent 9e2443d1aa
commit a788c9c80f
21 changed files with 244 additions and 108 deletions

View File

@@ -59,7 +59,7 @@ class MusicResponsiveListItem extends YTNode {
channel_id?: string
endpoint?: NavigationEndpoint
};
item_count?: number;
item_count?: string | undefined;
year?: string;
constructor(data: any) {
@@ -190,14 +190,21 @@ class MusicResponsiveListItem extends YTNode {
#parsePlaylist() {
this.id = this.endpoint?.browse?.id;
this.title = this.#flex_columns[0].key('title').instanceof(Text).toString();
this.item_count = parseInt(this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => run.text.match(/\d+ (song|songs)/))?.text.match(/\d+/g));
const item_count_run = this.#flex_columns[1].key('title')
.instanceof(Text).runs?.find((run) => run.text.match(/\d+ (song|songs)/));
this.item_count = item_count_run ? item_count_run.text : undefined;
const author = this.#flex_columns[1].key('title').instanceof(Text).runs?.find((run) => Reflect.get(run, 'endpoint')?.browse?.id.startsWith('UC')) as TextRun;
author && (this.author = {
name: author.text,
channel_id: author.endpoint?.browse?.id,
endpoint: author.endpoint
});
if (author) {
this.author = {
name: author.text,
channel_id: author.endpoint?.browse?.id,
endpoint: author.endpoint
};
}
}
}

View File

@@ -8,7 +8,20 @@ import { YTNode } from '../helpers';
class Playlist extends YTNode {
static type = 'Playlist';
constructor(data) {
id: string;
title: Text;
author: Text | PlaylistAuthor;
thumbnails: Thumbnail[];
video_count: Text;
video_count_short: Text;
first_videos;
share_url: string | null;
menu;
badges;
endpoint: NavigationEndpoint;
thumbnail_overlays;
constructor(data: any) {
super();
this.id = data.playlistId;
this.title = new Text(data.title);
@@ -17,7 +30,7 @@ class Playlist extends YTNode {
new Text(data.shortBylineText) :
new PlaylistAuthor(data.longBylineText, data.ownerBadges, null);
this.thumbnails = Thumbnail.fromResponse(data.thumbnail || { thumbnails: data.thumbnails.map((th) => th.thumbnails).flat(1) });
this.thumbnails = Thumbnail.fromResponse(data.thumbnail || { thumbnails: data.thumbnails.map((th: any) => 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) || [];

View File

@@ -6,12 +6,28 @@ import { YTNode } from '../helpers';
class PlaylistHeader extends YTNode {
static type = 'PlaylistHeader';
constructor(data) {
id: string;
title: Text;
stats: Text[];
brief_stats: Text[];
author: PlaylistAuthor;
description: Text;
num_videos: Text;
view_count: Text;
can_share: boolean;
can_delete: boolean;
is_editable: boolean;
privacy: string;
save_button;
shuffle_play_button;
menu;
constructor(data: any) {
super();
this.id = data.playlistId;
this.title = new Text(data.title);
this.stats = data.stats.map((stat) => new Text(stat));
this.brief_stats = data.briefStats.map((stat) => new Text(stat));
this.stats = data.stats.map((stat: any) => new Text(stat));
this.brief_stats = data.briefStats.map((stat: any) => new Text(stat));
this.author = new PlaylistAuthor({ ...data.ownerText, navigationEndpoint: data.ownerEndpoint }, data.ownerBadges, null);
this.description = new Text(data.descriptionText);
this.num_videos = new Text(data.numVideosText);

View File

@@ -6,7 +6,13 @@ import { YTNode } from '../helpers';
class PlaylistInfoCardContent extends YTNode {
static type = 'PlaylistInfoCardContent';
constructor(data) {
title: Text;
thumbnails: Thumbnail[];
video_count: Text;
channel_name: Text;
endpoint: NavigationEndpoint;
constructor(data: any) {
super();
this.title = new Text(data.playlistTitle);
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);

View File

@@ -3,7 +3,10 @@ import { YTNode } from '../helpers';
class PlaylistMetadata extends YTNode {
static type = 'PlaylistMetadata';
constructor(data) {
title: string;
description: string;
constructor(data: any) {
super();
this.title = data.title;
this.description = data.description || null;

View File

@@ -5,7 +5,17 @@ import { YTNode } from '../helpers';
class PlaylistPanel extends YTNode {
static type = 'PlaylistPanel';
constructor(data) {
title: string;
title_text: Text;
contents;
playlist_id: string;
is_infinite: boolean;
continuation: string;
is_editable: boolean;
preview_description: string;
num_items_to_show: string;
constructor(data: any) {
super();
this.title = data.title;
this.title_text = new Text(data.titleText);

View File

@@ -1,52 +0,0 @@
import Parser from '../index';
import Text from './misc/Text';
import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
import { timeToSeconds } from '../../utils/Utils';
import { YTNode } from '../helpers';
class PlaylistPanelVideo extends YTNode {
static type = 'PlaylistPanelVideo';
constructor(data) {
super();
this.title = new Text(data.title);
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.selected = data.selected;
this.video_id = data.videoId;
this.duration = {
text: new Text(data.lengthText).toString(),
seconds: timeToSeconds(new Text(data.lengthText).toString())
};
const album = new Text(data.longBylineText).runs?.find((run) => run.endpoint?.browse?.id.startsWith('MPR'));
const artists = new Text(data.longBylineText).runs?.filter((run) => run.endpoint?.browse?.id.startsWith('UC'));
this.author = new Text(data.shortBylineText).toString();
if (album) {
this.album = {
id: album.endpoint?.browse.id,
name: album.text,
year: new Text(data.longBylineText).runs.slice(-1)[0].text,
endpoint: album.endpoint
};
}
if (artists) {
this.artists = artists.map((artist) => ({
name: artist.text,
channel_id: artist.endpoint?.browse.id,
endpoint: artist.endpoint
}));
}
this.badges = Parser.parse(data.badges);
this.menu = Parser.parse(data.menu);
this.set_video_id = data.playlistSetVideoId;
}
}
export default PlaylistPanelVideo;

View File

@@ -0,0 +1,85 @@
import Parser from '../index';
import Text from './misc/Text';
import TextRun from './misc/TextRun';
import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
import { timeToSeconds } from '../../utils/Utils';
import { YTNode } from '../helpers';
class PlaylistPanelVideo extends YTNode {
static type = 'PlaylistPanelVideo';
title: Text;
thumbnail: Thumbnail[];
endpoint: NavigationEndpoint;
selected: boolean;
video_id: string;
duration: {
text: string;
seconds: number
};
author: string;
album?: {
id: string | undefined;
name: string;
year: string | undefined;
endpoint: NavigationEndpoint | undefined;
};
artists?: {
name: string;
channel_id: string | undefined;
endpoint: NavigationEndpoint | undefined;
}[];
badges;
menu;
set_video_id: string | undefined;
constructor(data: any) {
super();
this.title = new Text(data.title);
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.selected = data.selected;
this.video_id = data.videoId;
this.duration = {
text: new Text(data.lengthText).toString(),
seconds: timeToSeconds(new Text(data.lengthText).toString())
};
const album = new Text(data.longBylineText).runs?.find((run: any) => run.endpoint?.browse?.id.startsWith('MPR'));
const artists = new Text(data.longBylineText).runs?.filter((run: any) => run.endpoint?.browse?.id.startsWith('UC'));
this.author = new Text(data.shortBylineText).toString();
if (album) {
this.album = {
id: (album as TextRun).endpoint?.browse?.id,
name: (album as TextRun).text,
year: new Text(data.longBylineText).runs?.slice(-1)[0].text,
endpoint: (album as TextRun).endpoint
};
}
if (artists) {
this.artists = artists.map((artist) => ({
name: (artist as TextRun).text,
channel_id: (artist as TextRun).endpoint?.browse?.id,
endpoint: (artist as TextRun).endpoint
}));
}
this.badges = Parser.parse(data.badges);
this.menu = Parser.parse(data.menu);
this.set_video_id = data.playlistSetVideoId;
}
}
export default PlaylistPanelVideo;

View File

@@ -4,7 +4,9 @@ import { YTNode } from '../helpers';
class PlaylistSidebar extends YTNode {
static type = 'PlaylistSidebar';
constructor(data) {
items;
constructor(data: any) {
super();
this.items = Parser.parse(data.items);
}

View File

@@ -1,14 +1,22 @@
import Parser from '../index';
import NavigationEndpoint from './NavigationEndpoint';
import Text from './misc/Text';
import NavigationEndpoint from './NavigationEndpoint';
import { YTNode } from '../helpers';
class PlaylistSidebarPrimaryInfo extends YTNode {
static type = 'PlaylistSidebarPrimaryInfo';
constructor(data) {
stats: Text[];
thumbnail_renderer;
title: Text;
menu;
endpoint: NavigationEndpoint;
description: Text;
constructor(data: any) {
super();
this.stats = data.stats.map((stat) => new Text(stat));
this.stats = data.stats.map((stat: any) => new Text(stat));
this.thumbnail_renderer = Parser.parse(data.thumbnailRenderer);
this.title = new Text(data.title);
this.menu = data.menu && Parser.parse(data.menu);

View File

@@ -4,7 +4,10 @@ import { YTNode } from '../helpers';
class PlaylistSidebarSecondaryInfo extends YTNode {
static type = 'PlaylistSidebarSecondaryInfo';
constructor(data) {
owner;
button;
constructor(data: any) {
super();
this.owner = Parser.parse(data.videoOwner) || null;
this.button = Parser.parse(data.button) || null;

View File

@@ -8,7 +8,23 @@ import { YTNode } from '../helpers';
class PlaylistVideo extends YTNode {
static type = 'PlaylistVideo';
constructor(data) {
id: string;
index: Text;
title: Text;
author: PlaylistAuthor;
thumbnails: Thumbnail[];
thumbnail_overlays;
set_video_id: string | undefined;
endpoint: NavigationEndpoint;
is_playable: boolean;
menu;
duration: {
text: string;
seconds: number;
};
constructor(data: any) {
super();
this.id = data.videoId;
this.index = new Text(data.index);

View File

@@ -4,7 +4,12 @@ import { YTNode } from '../helpers';
class PlaylistVideoList extends YTNode {
static type = 'PlaylistVideoList';
constructor(data) {
id: string;
is_editable: boolean;
can_reorder: boolean;
videos;
constructor(data: any) {
super();
this.id = data.playlistId;
this.is_editable = data.isEditable;

View File

@@ -4,7 +4,9 @@ import { YTNode } from '../helpers';
class PlaylistVideoThumbnail extends YTNode {
static type = 'PlaylistVideoThumbnail';
constructor(data) {
thumbnail: Thumbnail[];
constructor(data: any) {
super();
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
}

View File

@@ -1,16 +1,19 @@
import Thumbnail from './misc/Thumbnail';
import { YTNode } from '../helpers';
import Thumbnail from './Thumbnail';
class EmojiRun extends YTNode {
static type = 'EmojiRun';
constructor(data) {
super();
class EmojiRun {
text: string;
emoji: {
emoji_id: string;
shortcuts: string[];
search_terms: string[];
image: Thumbnail[];
};
constructor(data: any) {
this.text =
data.emoji?.emojiId ||
data.emoji?.shortcuts?.[0] ||
null;
'';
this.emoji = {
emoji_id: data.emoji.emojiId,

View File

@@ -1,8 +1,8 @@
import Author from './Author';
class PlaylistAuthor extends Author {
constructor(data) {
super(data);
constructor(item, badges, thumbs) {
super(item, badges, thumbs);
delete this.badges;
delete this.is_verified;
delete this.is_verified_artist;

View File

@@ -1,5 +1,5 @@
import TextRun from './TextRun';
import EmojiRun from '../EmojiRun';
import EmojiRun from './EmojiRun';
class Text {
text: string;

View File

@@ -1,7 +1,10 @@
import NavigationEndpoint from '../NavigationEndpoint';
class TextRun {
constructor(data) {
text: string;
endpoint: NavigationEndpoint | undefined;
constructor(data: any) {
this.text = data.text;
this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : undefined;
}