@np-dev/youtubei-js
Version:
A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).
375 lines • 15.9 kB
JavaScript
var _Innertube_session;
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
import Session from './core/Session.js';
import NavigationEndpoint from './parser/classes/NavigationEndpoint.js';
import Channel from './parser/youtube/Channel.js';
import Comments from './parser/youtube/Comments.js';
import Guide from './parser/youtube/Guide.js';
import HashtagFeed from './parser/youtube/HashtagFeed.js';
import History from './parser/youtube/History.js';
import HomeFeed from './parser/youtube/HomeFeed.js';
import Library from './parser/youtube/Library.js';
import NotificationsMenu from './parser/youtube/NotificationsMenu.js';
import Playlist from './parser/youtube/Playlist.js';
import Search from './parser/youtube/Search.js';
import VideoInfo from './parser/youtube/VideoInfo.js';
import ShortsVideoInfo from './parser/ytshorts/VideoInfo.js';
import { Kids, Music, Studio } from './core/clients/index.js';
import { AccountManager, InteractionManager, PlaylistManager } from './core/managers/index.js';
import { Feed, TabbedFeed } from './core/mixins/index.js';
import * as Proto from './proto/index.js';
import * as Constants from './utils/Constants.js';
import { InnertubeError, generateRandomString, throwIfMissing } from './utils/Utils.js';
import { BrowseEndpoint, GetNotificationMenuEndpoint, GuideEndpoint, NextEndpoint, PlayerEndpoint, ResolveURLEndpoint, SearchEndpoint, Reel } from './core/endpoints/index.js';
import { GetUnseenCountEndpoint } from './core/endpoints/notification/index.js';
import { encodeReelSequence } from './proto/index.js';
/**
* Provides access to various services and modules in the YouTube API.
*/
class Innertube {
constructor(session) {
_Innertube_session.set(this, void 0);
__classPrivateFieldSet(this, _Innertube_session, session, "f");
}
static create(config = {}) {
return __awaiter(this, void 0, void 0, function* () {
return new Innertube(yield Session.create(config));
});
}
/**
* Retrieves video info.
* @param target - The video id or `NavigationEndpoint`.
* @param client - The client to use.
*/
getInfo(target, client) {
var _a, _b, _c, _d, _e;
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ target });
let next_payload;
if (target instanceof NavigationEndpoint) {
next_payload = NextEndpoint.build({
video_id: (_a = target.payload) === null || _a === void 0 ? void 0 : _a.videoId,
playlist_id: (_b = target.payload) === null || _b === void 0 ? void 0 : _b.playlistId,
params: (_c = target.payload) === null || _c === void 0 ? void 0 : _c.params,
playlist_index: (_d = target.payload) === null || _d === void 0 ? void 0 : _d.index
});
}
else if (typeof target === 'string') {
next_payload = NextEndpoint.build({
video_id: target
});
}
else {
throw new InnertubeError('Invalid target, expected either a video id or a valid NavigationEndpoint', target);
}
if (!next_payload.videoId)
throw new InnertubeError('Video id cannot be empty', next_payload);
const player_payload = PlayerEndpoint.build({
video_id: next_payload.videoId,
playlist_id: next_payload === null || next_payload === void 0 ? void 0 : next_payload.playlistId,
client: client,
sts: (_e = __classPrivateFieldGet(this, _Innertube_session, "f").player) === null || _e === void 0 ? void 0 : _e.sts
});
const player_response = this.actions.execute(PlayerEndpoint.PATH, player_payload);
const next_response = this.actions.execute(NextEndpoint.PATH, next_payload);
const response = yield Promise.all([player_response, next_response]);
const cpn = generateRandomString(16);
return new VideoInfo(response, this.actions, cpn);
});
}
/**
* Retrieves basic video info.
* @param video_id - The video id.
* @param client - The client to use.
*/
getBasicInfo(video_id, client) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ video_id });
const response = yield this.actions.execute(PlayerEndpoint.PATH, PlayerEndpoint.build({
video_id: video_id,
client: client,
sts: (_a = __classPrivateFieldGet(this, _Innertube_session, "f").player) === null || _a === void 0 ? void 0 : _a.sts
}));
const cpn = generateRandomString(16);
return new VideoInfo([response], this.actions, cpn);
});
}
/**
* Retrieves shorts info.
* @param short_id - The short id.
* @param client - The client to use.
*/
getShortsWatchItem(short_id, client) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ short_id });
const watchResponse = this.actions.execute(Reel.WatchEndpoint.PATH, Reel.WatchEndpoint.build({
short_id: short_id,
client: client
}));
const sequenceResponse = this.actions.execute(Reel.WatchSequenceEndpoint.PATH, Reel.WatchSequenceEndpoint.build({
sequenceParams: encodeReelSequence(short_id)
}));
const response = yield Promise.all([watchResponse, sequenceResponse]);
return new ShortsVideoInfo(response, this.actions);
});
}
/**
* Searches a given query.
* @param query - The search query.
* @param filters - Search filters.
*/
search(query, filters = {}) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ query });
const response = yield this.actions.execute(SearchEndpoint.PATH, SearchEndpoint.build({
query, params: filters ? Proto.encodeSearchFilters(filters) : undefined
}));
return new Search(this.actions, response);
});
}
/**
* Retrieves search suggestions for a given query.
* @param query - The search query.
*/
getSearchSuggestions(query) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ query });
const url = new URL(`${Constants.URLS.YT_SUGGESTIONS}search`);
url.searchParams.set('q', query);
url.searchParams.set('hl', __classPrivateFieldGet(this, _Innertube_session, "f").context.client.hl);
url.searchParams.set('gl', __classPrivateFieldGet(this, _Innertube_session, "f").context.client.gl);
url.searchParams.set('ds', 'yt');
url.searchParams.set('client', 'youtube');
url.searchParams.set('xssi', 't');
url.searchParams.set('oe', 'UTF');
const response = yield __classPrivateFieldGet(this, _Innertube_session, "f").http.fetch(url);
const response_data = yield response.text();
const data = JSON.parse(response_data.replace(')]}\'', ''));
const suggestions = data[1].map((suggestion) => suggestion[0]);
return suggestions;
});
}
/**
* Retrieves comments for a video.
* @param video_id - The video id.
* @param sort_by - Sorting options.
*/
getComments(video_id, sort_by) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ video_id });
const response = yield this.actions.execute(NextEndpoint.PATH, NextEndpoint.build({
continuation: Proto.encodeCommentsSectionParams(video_id, {
sort_by: sort_by || 'TOP_COMMENTS'
})
}));
return new Comments(this.actions, response.data);
});
}
/**
* Retrieves YouTube's home feed (aka recommendations).
*/
getHomeFeed() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FEwhat_to_watch' }));
return new HomeFeed(this.actions, response);
});
}
/**
* Retrieves YouTube's content guide.
*/
getGuide() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(GuideEndpoint.PATH);
return new Guide(response.data);
});
}
/**
* Returns the account's library.
*/
getLibrary() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FElibrary' }));
return new Library(this.actions, response);
});
}
/**
* Retrieves watch history.
* Which can also be achieved with {@link getLibrary}.
*/
getHistory() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: 'FEhistory' }));
return new History(this.actions, response);
});
}
/**
* Retrieves trending content.
*/
getTrending() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(BrowseEndpoint.PATH, Object.assign(Object.assign({}, BrowseEndpoint.build({ browse_id: 'FEtrending' })), { parse: true }));
return new TabbedFeed(this.actions, response);
});
}
/**
* Retrieves subscriptions feed.
*/
getSubscriptionsFeed() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(BrowseEndpoint.PATH, Object.assign(Object.assign({}, BrowseEndpoint.build({ browse_id: 'FEsubscriptions' })), { parse: true }));
return new Feed(this.actions, response);
});
}
/**
* Retrieves contents for a given channel.
* @param id - Channel id
*/
getChannel(id) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ id });
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: id }));
return new Channel(this.actions, response);
});
}
/**
* Retrieves notifications.
*/
getNotifications() {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(GetNotificationMenuEndpoint.PATH, GetNotificationMenuEndpoint.build({
notifications_menu_request_type: 'NOTIFICATIONS_MENU_REQUEST_TYPE_INBOX'
}));
return new NotificationsMenu(this.actions, response);
});
}
/**
* Retrieves unseen notifications count.
*/
getUnseenNotificationsCount() {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(GetUnseenCountEndpoint.PATH);
// TODO: properly parse this
return ((_a = response.data) === null || _a === void 0 ? void 0 : _a.unseenCount) || ((_d = (_c = (_b = response.data) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c[0].updateNotificationsUnseenCountAction) === null || _d === void 0 ? void 0 : _d.unseenCount) || 0;
});
}
/**
* Retrieves playlist contents.
* @param id - Playlist id
*/
getPlaylist(id) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ id });
if (!id.startsWith('VL')) {
id = `VL${id}`;
}
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ browse_id: id }));
return new Playlist(this.actions, response);
});
}
/**
* Retrieves a given hashtag's page.
* @param hashtag - The hashtag to fetch.
*/
getHashtag(hashtag) {
return __awaiter(this, void 0, void 0, function* () {
throwIfMissing({ hashtag });
const response = yield this.actions.execute(BrowseEndpoint.PATH, BrowseEndpoint.build({
browse_id: 'FEhashtag',
params: Proto.encodeHashtag(hashtag)
}));
return new HashtagFeed(this.actions, response);
});
}
/**
* An alternative to {@link download}.
* Returns deciphered streaming data.
*
* If you wish to retrieve the video info too, have a look at {@link getBasicInfo} or {@link getInfo}.
* @param video_id - The video id.
* @param options - Format options.
*/
getStreamingData(video_id, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const info = yield this.getBasicInfo(video_id);
return info.chooseFormat(options);
});
}
/**
* Downloads a given video. If you only need the direct download link see {@link getStreamingData}.
* If you wish to retrieve the video info too, have a look at {@link getBasicInfo} or {@link getInfo}.
* @param video_id - The video id.
* @param options - Download options.
*/
download(video_id, options) {
return __awaiter(this, void 0, void 0, function* () {
const info = yield this.getBasicInfo(video_id, options === null || options === void 0 ? void 0 : options.client);
return info.download(options);
});
}
/**
* Resolves the given URL.
* @param url - The URL.
*/
resolveURL(url) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield this.actions.execute(ResolveURLEndpoint.PATH, Object.assign(Object.assign({}, ResolveURLEndpoint.build({ url })), { parse: true }));
return response.endpoint;
});
}
call(endpoint, args) {
return endpoint.call(this.actions, args);
}
/**
* An interface for interacting with YouTube Music.
*/
get music() {
return new Music(__classPrivateFieldGet(this, _Innertube_session, "f"));
}
/**
* An interface for interacting with YouTube Studio.
*/
get studio() {
return new Studio(__classPrivateFieldGet(this, _Innertube_session, "f"));
}
/**
* An interface for interacting with YouTube Kids.
*/
get kids() {
return new Kids(__classPrivateFieldGet(this, _Innertube_session, "f"));
}
/**
* An interface for managing and retrieving account information.
*/
get account() {
return new AccountManager(__classPrivateFieldGet(this, _Innertube_session, "f").actions);
}
/**
* An interface for managing playlists.
*/
get playlist() {
return new PlaylistManager(__classPrivateFieldGet(this, _Innertube_session, "f").actions);
}
/**
* An interface for directly interacting with certain YouTube features.
*/
get interact() {
return new InteractionManager(__classPrivateFieldGet(this, _Innertube_session, "f").actions);
}
/**
* An internal class used to dispatch requests.
*/
get actions() {
return __classPrivateFieldGet(this, _Innertube_session, "f").actions;
}
/**
* The session used by this instance.
*/
get session() {
return __classPrivateFieldGet(this, _Innertube_session, "f");
}
}
_Innertube_session = new WeakMap();
export default Innertube;
//# sourceMappingURL=Innertube.js.map