Files
YouTube.js/src/parser/youtube/Library.ts
Daniel Wykerd 2ccbe2ce62 refactor!: cleanup platform support (#306)
* refactor!: cleanup platform support

* chore: lint

* fix: web platform

* feat: provide UniversalCache

Provide UniversalCache as a wrapper around Platform.shim.Cache.

* fix: invalid import

* refactor: remove isolated-vm support

* fix: type info

* refactor: cleanup exports

* fix: mark jintr as external dependency

In the bundled CJS node build, mark jintr as external.

* chore: add additional exports

web exports provide a way to select web implementation manually without
relying on the bundler to select it correctly from the "exports" field

web points to src/platform/web.js
web.bundle points to bundle/browser.js
web.bundle.browser points to bundle/browser.min.js

agnostic exports provide users of the library to provide their own
platform implementation without first importing the default one.

agnostic points to src/platform/lib.ts

* fix: toDash on web

* revert: eval is synchronous

* fix: use serializeDOM in FormatUtils

* ci: automate releases with `release-please`

* chore: clean up workflow files

* ci: fix NPM publish action

---------

Co-authored-by: LuanRT <luan.lrt4@gmail.com>
2023-02-12 04:21:44 -03:00

95 lines
2.8 KiB
TypeScript

import Parser, { ParsedResponse } from '../index.js';
import type Actions from '../../core/Actions.js';
import type { ApiResponse } from '../../core/Actions.js';
import { InnertubeError } from '../../utils/Utils.js';
import Feed from '../../core/Feed.js';
import History from './History.js';
import Playlist from './Playlist.js';
import Menu from '../classes/menus/Menu.js';
import Shelf from '../classes/Shelf.js';
import Button from '../classes/Button.js';
import ProfileColumnStats from '../classes/ProfileColumnStats.js';
import ProfileColumnUserInfo from '../classes/ProfileColumnUserInfo.js';
class Library {
#actions: Actions;
#page: ParsedResponse;
profile: {
stats?: ProfileColumnStats;
user_info?: ProfileColumnUserInfo;
};
sections;
constructor(response: ApiResponse, actions: Actions) {
this.#actions = actions;
this.#page = Parser.parseResponse(response);
const stats = this.#page.contents_memo.getType(ProfileColumnStats)?.[0];
const user_info = this.#page.contents_memo.getType(ProfileColumnUserInfo)?.[0];
this.profile = { stats, user_info };
const shelves = this.#page.contents_memo.getType(Shelf);
this.sections = shelves.map((shelf: Shelf) => ({
type: shelf.icon_type,
title: shelf.title,
contents: shelf.content?.key('items').array() || [],
getAll: () => this.#getAll(shelf)
}));
}
async #getAll(shelf: Shelf): Promise<Playlist | History | Feed> {
if (!shelf.menu?.as(Menu).hasKey('top_level_buttons'))
throw new InnertubeError(`The ${shelf.title.text} shelf doesn't have more items`);
const button = shelf.menu.as(Menu).top_level_buttons.firstOfType(Button);
if (!button)
throw new InnertubeError('Did not find target button.');
const page = await button.as(Button).endpoint.call(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;