refactor(ytmusic): rewrite HomeFeed to TypeScript

This commit is contained in:
LuanRT
2022-07-22 03:14:56 -03:00
parent 8b9cd236ae
commit 851afddf51
3 changed files with 77 additions and 55 deletions

View File

@@ -9,31 +9,30 @@ class MusicTwoRowItem extends YTNode {
constructor(data) { constructor(data) {
super(); super();
this.id =
this.endpoint.browse?.id ||
this.endpoint.watch?.video_id;
this.title = new Text(data.title); this.title = new Text(data.title);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint); this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.id =
this.endpoint?.browse?.id ||
this.endpoint?.watch?.video_id;
this.subtitle = new Text(data.subtitle); this.subtitle = new Text(data.subtitle);
this.badges = Parser.parse(data.subtitleBadges); this.badges = Parser.parse(data.subtitleBadges);
switch (this.endpoint?.browse?.page_type) { switch (this.endpoint?.browse?.page_type) {
case 'MUSIC_PAGE_TYPE_ARTIST': case 'MUSIC_PAGE_TYPE_ARTIST':
this.type = 'artist'; this.item_type = 'artist';
this.subscribers = this.subtitle.toString(); this.subscribers = this.subtitle.toString();
break; break;
case 'MUSIC_PAGE_TYPE_PLAYLIST': case 'MUSIC_PAGE_TYPE_PLAYLIST':
this.type = 'playlist'; this.item_type = 'playlist';
this.item_count = parseInt(this.subtitle.runs this.item_count = this.subtitle.runs
.find((run) => run.text .find((run) => run.text.match(/\d+ songs|song/))?.item || null;
.match(/\d+ (songs|song)/))?.text
.match(/\d+/g)) || null;
break; break;
case 'MUSIC_PAGE_TYPE_ALBUM': case 'MUSIC_PAGE_TYPE_ALBUM':
this.type = 'album'; this.item_type = 'album';
const artists = this.subtitle.runs.filter((run) => run.endpoint.browse?.id.startsWith('UC')); const artists = this.subtitle.runs.filter((run) => run.endpoint?.browse?.id.startsWith('UC'));
if (artists) { if (artists) {
this.artists = artists.map((artist) => ({ this.artists = artists.map((artist) => ({
name: artist.text, name: artist.text,
@@ -47,16 +46,16 @@ class MusicTwoRowItem extends YTNode {
break; break;
default: default:
if (this.subtitle.runs[0].text !== 'Song') { if (this.subtitle.runs[0].text !== 'Song') {
this.type = 'video'; this.item_type = 'video';
} else { } else {
this.type = 'song'; this.item_type = 'song';
} }
if (this.type == 'video') { if (this.item_type == 'video') {
this.views = this.subtitle.runs this.views = this.subtitle.runs
.find((run) => run.text.match(/(.*?) views/)).text; .find((run) => run.text.match(/(.*?) views/)).text;
const author = this.subtitle.runs.find((run) => run.endpoint.browse?.id.startsWith('UC')); const author = this.subtitle.runs.find((run) => run.endpoint?.browse?.id.startsWith('UC'));
if (author) { if (author) {
this.author = { this.author = {
name: author.text, name: author.text,
@@ -65,7 +64,7 @@ class MusicTwoRowItem extends YTNode {
}; };
} }
} else { } else {
const artists = this.subtitle.runs.filter((run) => run.endpoint.browse?.id.startsWith('UC')); const artists = this.subtitle.runs.filter((run) => run.endpoint?.browse?.id.startsWith('UC'));
if (artists) { if (artists) {
this.artists = artists.map((artist) => ({ this.artists = artists.map((artist) => ({
name: artist.text, name: artist.text,
@@ -83,4 +82,4 @@ class MusicTwoRowItem extends YTNode {
} }
} }
export default MusicTwoRowItem; export default MusicTwoRowItem;

View File

@@ -1,37 +0,0 @@
import Parser from '../index';
class HomeFeed {
#page;
#actions;
#continuation;
/**
* @param {object} response - API response.
* @param {import('../../core/Actions').default} actions
*/
constructor(response, actions) {
this.#actions = actions;
this.#page = Parser.parseResponse(response.data);
const tab = this.#page.contents.tabs.get({ title: 'Home' });
this.#continuation = tab.content?.continuation || this.#page.continuation_contents.continuation;
/** @type {import('../classes/MusicCarouselShelf')[]} */
this.sections = tab.content?.contents || this.#page.continuation_contents.contents;
}
/**
* Retrieves home feed continuation.
* @returns {Promise.<HomeFeed>}
*/
async getContinuation() {
const response = await this.#actions.browse(this.#continuation, { is_ctoken: true, client: 'YTMUSIC' });
return new HomeFeed(response, this.#actions);
}
get page() {
return this.#page;
}
}
export default HomeFeed;

View File

@@ -0,0 +1,60 @@
import Parser, { ParsedResponse } from '../index';
import Actions, { AxioslikeResponse } from '../../core/Actions';
import { InnertubeError } from '../../utils/Utils';
import MusicCarouselShelfBasicHeader from '../classes/MusicCarouselShelfBasicHeader';
import MusicTwoRowItem from '../classes/MusicTwoRowItem';
class HomeFeed {
#page;
#actions;
#continuation;
sections;
constructor(response: AxioslikeResponse | ParsedResponse, actions: Actions) {
this.#actions = actions;
this.#page = Parser.parseResponse((response as AxioslikeResponse).data);
const tab = this.#page.contents.item().key('tabs').parsed().array().get({ selected: true });
if (!tab)
throw new InnertubeError('Could not get Home tab.');
let contents;
if (tab.key('content').isNull()) {
this.#continuation = this.#page.continuation_contents?.key('continuation').string();
contents = this.#page.continuation_contents?.key('contents').array();
} else {
this.#continuation = tab.key('content').parsed().item().key('continuation').string();
contents = tab.key('content').parsed().item().key('contents').parsed().array();
}
this.sections = contents?.map((content) => ({
header: content.header.item() as MusicCarouselShelfBasicHeader,
contents: content.contents.array() as Array<MusicTwoRowItem>
}));
}
/**
* Retrieves home feed continuation.
*/
async getContinuation(): Promise<HomeFeed> {
if (!this.#continuation)
throw new InnertubeError('Continuation not found.');
const response = await this.#actions.browse(this.#continuation, { is_ctoken: true, client: 'YTMUSIC' });
return new HomeFeed(response, this.#actions);
}
get has_continuation(): boolean {
return !!this.#continuation;
}
get page() {
return this.#page;
}
}
export default HomeFeed;