mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-23 23:09:28 +00:00
refactor: rewrite Library to TypeScript
This commit is contained in:
@@ -14,7 +14,7 @@ class Shelf extends YTNode {
|
||||
this.endpoint = new NavigationEndpoint(data.endpoint);
|
||||
}
|
||||
|
||||
this.content = Parser.parse(data.content) || [];
|
||||
this.content = Parser.parse(data.content) || null;
|
||||
|
||||
if (data.icon?.iconType) {
|
||||
this.icon_type = data.icon?.iconType;
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import Parser from '../index';
|
||||
import History from './History';
|
||||
import Playlist from './Playlist';
|
||||
import Feed from '../../core/Feed';
|
||||
import { observe } from '../helpers';
|
||||
|
||||
class Library {
|
||||
#actions;
|
||||
#page;
|
||||
|
||||
/**
|
||||
* @param {object} response - API response.
|
||||
* @param {import('../../core/Actions').default} actions
|
||||
*/
|
||||
constructor(response, actions) {
|
||||
this.#actions = actions;
|
||||
this.#page = Parser.parseResponse(response);
|
||||
|
||||
const tab = this.#page.contents.tabs.get({ selected: true });
|
||||
const shelves = tab.content.contents.map((section) => section.contents[0]);
|
||||
|
||||
const stats = this.#page.contents.secondary_contents.items.get({ type: 'ProfileColumnStats' }).items;
|
||||
const user_info = this.#page.contents.secondary_contents.items.get({ type: 'ProfileColumnUserInfo' });
|
||||
|
||||
this.profile = { stats, user_info };
|
||||
|
||||
/** @type {{ type: string, title: import('../classes/misc/Text'), contents: object[], getAll: Promise.<Playlist | History | Feed> }[] } */
|
||||
this.sections = observe(shelves.map((shelf) => ({
|
||||
type: shelf.icon_type,
|
||||
title: shelf.title,
|
||||
contents: shelf.content.items,
|
||||
getAll: () => this.#getAll(shelf)
|
||||
})));
|
||||
}
|
||||
|
||||
async #getAll(shelf) {
|
||||
if (!shelf.menu?.top_level_buttons)
|
||||
throw new Error(`The ${shelf.title.text} section doesn't have more items`);
|
||||
|
||||
const button = await shelf.menu.top_level_buttons.get({ text: 'See all' });
|
||||
const page = await button.endpoint.call(this.#actions);
|
||||
|
||||
switch (shelf.icon_type) {
|
||||
case 'LIKE':
|
||||
case 'WATCH_LATER':
|
||||
return new Playlist(this.#actions, page, true);
|
||||
case 'WATCH_HISTORY':
|
||||
return new History(this.#actions, page, true);
|
||||
case 'CONTENT_CUT':
|
||||
return new Feed(this.#actions, page, true);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
get history() {
|
||||
return this.sections.get({ type: 'WATCH_HISTORY' });
|
||||
}
|
||||
|
||||
get watch_later() {
|
||||
return this.sections.get({ type: 'WATCH_LATER' });
|
||||
}
|
||||
|
||||
get liked_videos() {
|
||||
return this.sections.get({ type: 'LIKE' });
|
||||
}
|
||||
|
||||
get playlists() {
|
||||
return this.sections.get({ type: 'PLAYLISTS' });
|
||||
}
|
||||
|
||||
get clips() {
|
||||
return this.sections.get({ type: 'CONTENT_CUT' });
|
||||
}
|
||||
|
||||
get page() {
|
||||
return this.#page;
|
||||
}
|
||||
}
|
||||
|
||||
export default Library;
|
||||
106
src/parser/youtube/Library.ts
Normal file
106
src/parser/youtube/Library.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import Parser, { ParsedResponse } from '..';
|
||||
import Actions, { AxioslikeResponse } from '../../core/Actions';
|
||||
import { InnertubeError } from '../../utils/Utils';
|
||||
|
||||
import Feed from '../../core/Feed';
|
||||
import History from './History';
|
||||
import Playlist from './Playlist';
|
||||
|
||||
import Tab from '../classes/Tab';
|
||||
import Menu from '../classes/menus/Menu';
|
||||
import Shelf from '../classes/Shelf';
|
||||
import Button from '../classes/Button';
|
||||
import SectionList from '../classes/SectionList';
|
||||
import ItemSection from '../classes/ItemSection';
|
||||
import TwoColumnBrowseResults from '../classes/TwoColumnBrowseResults';
|
||||
|
||||
import ProfileColumn from '../classes/ProfileColumn';
|
||||
import ProfileColumnStats from '../classes/ProfileColumnStats';
|
||||
import ProfileColumnUserInfo from '../classes/ProfileColumnUserInfo';
|
||||
|
||||
class Library {
|
||||
#actions;
|
||||
#page;
|
||||
|
||||
profile;
|
||||
sections;
|
||||
|
||||
constructor(response: AxioslikeResponse, actions: Actions) {
|
||||
this.#actions = actions;
|
||||
this.#page = Parser.parseResponse(response);
|
||||
|
||||
const two_col = this.#page.contents.item().as(TwoColumnBrowseResults);
|
||||
|
||||
if (!two_col)
|
||||
throw new InnertubeError('Response did not have a TwoColumnBrowseResults.');
|
||||
|
||||
const tab = two_col.tabs.array().as(Tab).get({ selected: true });
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
|
||||
const stats = two_col.secondary_contents.item().as(ProfileColumn).items.array().get({ type: 'ProfileColumnStats' })?.as(ProfileColumnStats) || null;
|
||||
const user_info = two_col.secondary_contents.item().as(ProfileColumn).items.array().get({ type: 'ProfileColumnUserInfo' })?.as(ProfileColumnUserInfo) || null;
|
||||
|
||||
this.profile = { stats, user_info };
|
||||
|
||||
const shelves = tab.content.item().as(SectionList).contents.array().as(ItemSection).map((is: ItemSection) => is.contents?.firstOfType(Shelf));
|
||||
|
||||
this.sections = shelves.map((shelf: any) => ({
|
||||
type: shelf.icon_type,
|
||||
title: shelf.title,
|
||||
contents: shelf.content?.item().items.array() || [],
|
||||
getAll: () => this.#getAll(shelf)
|
||||
}));
|
||||
}
|
||||
|
||||
async #getAll(shelf: Shelf): Promise<Playlist | History | Feed> {
|
||||
if (!shelf.menu?.item().as(Menu).hasKey('top_level_buttons'))
|
||||
throw new InnertubeError(`The ${shelf.title.text} shelf doesn't have more items`);
|
||||
|
||||
const button = await shelf.menu.item().as(Menu).top_level_buttons.get({ text: 'See all' });
|
||||
|
||||
if (!button)
|
||||
throw new InnertubeError('Did not find target button.');
|
||||
|
||||
const page = await button.as(Button).endpoint.callTest(this.#actions, { parse: true });
|
||||
|
||||
switch (shelf.icon_type) {
|
||||
case 'LIKE':
|
||||
case 'WATCH_LATER':
|
||||
return new Playlist(this.#actions, page, true);
|
||||
case 'WATCH_HISTORY':
|
||||
return new History(this.#actions, page, true);
|
||||
case 'CONTENT_CUT':
|
||||
return new Feed(this.#actions, page, true);
|
||||
default:
|
||||
throw new InnertubeError('Target shelf not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
get history() {
|
||||
return this.sections.find((section) => section.type === 'WATCH_HISTORY');
|
||||
}
|
||||
|
||||
get watch_later() {
|
||||
return this.sections.find((section) => section.type === 'WATCH_LATER');
|
||||
}
|
||||
|
||||
get liked_videos() {
|
||||
return this.sections.find((section) => section.type === 'LIKE');
|
||||
}
|
||||
|
||||
get playlists() {
|
||||
return this.sections.find((section) => section.type === 'PLAYLISTS');
|
||||
}
|
||||
|
||||
get clips() {
|
||||
return this.sections.find((section) => section.type === 'CONTENT_CUT');
|
||||
}
|
||||
|
||||
get page(): ParsedResponse {
|
||||
return this.#page;
|
||||
}
|
||||
}
|
||||
|
||||
export default Library;
|
||||
Reference in New Issue
Block a user