UNPKG

@np-dev/youtubei-js

Version:

A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).

185 lines 10.3 kB
var _HTTPClient_instances, _HTTPClient_session, _HTTPClient_cookie, _HTTPClient_fetch, _HTTPClient_adjustContext; import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; import * as Constants from './Constants.js'; import { Platform, generateSidAuth, getRandomUserAgent, getStringBetweenStrings, InnertubeError } from './Utils.js'; class HTTPClient { constructor(session, cookie, fetch) { _HTTPClient_instances.add(this); _HTTPClient_session.set(this, void 0); _HTTPClient_cookie.set(this, void 0); _HTTPClient_fetch.set(this, void 0); __classPrivateFieldSet(this, _HTTPClient_session, session, "f"); __classPrivateFieldSet(this, _HTTPClient_cookie, cookie, "f"); __classPrivateFieldSet(this, _HTTPClient_fetch, fetch || Platform.shim.fetch, "f"); } get fetch_function() { return __classPrivateFieldGet(this, _HTTPClient_fetch, "f"); } fetch(input, init) { return __awaiter(this, void 0, void 0, function* () { const innertube_url = Constants.URLS.API.PRODUCTION_1 + __classPrivateFieldGet(this, _HTTPClient_session, "f").api_version; const baseURL = (init === null || init === void 0 ? void 0 : init.baseURL) || innertube_url; const request_url = typeof input === 'string' ? (!baseURL.endsWith('/') && !input.startsWith('/')) ? new URL(`${baseURL}/${input}`) : new URL(baseURL + input) : input instanceof URL ? input : new URL(input.url, baseURL); const headers = (init === null || init === void 0 ? void 0 : init.headers) || (input instanceof Platform.shim.Request ? input.headers : new Platform.shim.Headers()) || new Platform.shim.Headers(); const body = (init === null || init === void 0 ? void 0 : init.body) || (input instanceof Platform.shim.Request ? input.body : undefined); const request_headers = new Platform.shim.Headers(headers); request_headers.set('Accept', '*/*'); request_headers.set('Accept-Language', '*'); request_headers.set('X-Goog-Visitor-Id', __classPrivateFieldGet(this, _HTTPClient_session, "f").context.client.visitorData || ''); request_headers.set('X-Origin', request_url.origin); request_headers.set('X-Youtube-Client-Version', __classPrivateFieldGet(this, _HTTPClient_session, "f").context.client.clientVersion || ''); if (Platform.shim.server) { request_headers.set('User-Agent', getRandomUserAgent('desktop')); request_headers.set('origin', request_url.origin); } request_url.searchParams.set('key', __classPrivateFieldGet(this, _HTTPClient_session, "f").key); request_url.searchParams.set('prettyPrint', 'false'); request_url.searchParams.set('alt', 'json'); const content_type = request_headers.get('Content-Type'); let request_body = body; let is_web_kids = false; const is_innertube_req = baseURL === innertube_url || baseURL === Constants.URLS.YT_UPLOAD; // Copy context into payload when possible if (content_type === 'application/json' && is_innertube_req && (typeof body === 'string')) { const json = JSON.parse(body); const n_body = Object.assign(Object.assign({}, json), { // Deep copy since we're gonna be modifying it context: JSON.parse(JSON.stringify(__classPrivateFieldGet(this, _HTTPClient_session, "f").context)) }); __classPrivateFieldGet(this, _HTTPClient_instances, "m", _HTTPClient_adjustContext).call(this, n_body.context, n_body.client); request_headers.set('x-youtube-client-version', n_body.context.client.clientVersion); delete n_body.client; if (Platform.shim.server) { if (n_body.context.client.clientName === 'ANDROID' || n_body.context.client.clientName === 'ANDROID_MUSIC') { request_headers.set('User-Agent', Constants.CLIENTS.ANDROID.USER_AGENT); } else if (n_body.context.client.clientName === 'iOS') { request_headers.set('User-Agent', Constants.CLIENTS.iOS.USER_AGENT); } } is_web_kids = n_body.context.client.clientName === 'WEB_KIDS'; request_body = JSON.stringify(n_body); } // Authenticate (NOTE: YouTube Kids does not support regular bearer tokens) if (__classPrivateFieldGet(this, _HTTPClient_session, "f").logged_in && is_innertube_req && !is_web_kids) { const oauth = __classPrivateFieldGet(this, _HTTPClient_session, "f").oauth; if (oauth.validateCredentials()) { yield oauth.refreshIfRequired(); request_headers.set('authorization', `Bearer ${oauth.credentials.access_token}`); // Remove API key as it is not required when using oauth. request_url.searchParams.delete('key'); } if (__classPrivateFieldGet(this, _HTTPClient_cookie, "f")) { const papisid = getStringBetweenStrings(__classPrivateFieldGet(this, _HTTPClient_cookie, "f"), 'PAPISID=', ';'); if (papisid) { request_headers.set('authorization', yield generateSidAuth(papisid)); request_headers.set('x-goog-authuser', __classPrivateFieldGet(this, _HTTPClient_session, "f").account_index.toString()); } request_headers.set('cookie', __classPrivateFieldGet(this, _HTTPClient_cookie, "f")); } } const request = new Platform.shim.Request(request_url, input instanceof Platform.shim.Request ? input : init); const response = yield __classPrivateFieldGet(this, _HTTPClient_fetch, "f").call(this, request, { body: request_body, headers: request_headers, credentials: 'include', redirect: input instanceof Platform.shim.Request ? input.redirect : (init === null || init === void 0 ? void 0 : init.redirect) || 'follow' }); // Check if 2xx if (response.ok) { return response; } throw new InnertubeError(`Request to ${response.url} failed with status ${response.status}`, yield response.text()); }); } } _HTTPClient_session = new WeakMap(), _HTTPClient_cookie = new WeakMap(), _HTTPClient_fetch = new WeakMap(), _HTTPClient_instances = new WeakSet(), _HTTPClient_adjustContext = function _HTTPClient_adjustContext(ctx, client) { if (client === 'ANDROID' || client === 'YTMUSIC_ANDROID' || client === 'YTMUSIC_ANDROID' || client === 'YTSTUDIO_ANDROID') { ctx.client.androidSdkVersion = Constants.CLIENTS.ANDROID.SDK_VERSION; ctx.client.userAgent = Constants.CLIENTS.ANDROID.USER_AGENT; ctx.client.osName = 'Android'; ctx.client.osVersion = '10'; ctx.client.platform = 'MOBILE'; } switch (client) { case 'iOS': ctx.client.deviceModel = Constants.CLIENTS.iOS.DEVICE_MODEL; ctx.client.clientVersion = Constants.CLIENTS.iOS.VERSION; ctx.client.clientName = Constants.CLIENTS.iOS.NAME; ctx.client.platform = 'MOBILE'; break; case 'YTMUSIC': ctx.client.clientVersion = Constants.CLIENTS.YTMUSIC.VERSION; ctx.client.clientName = Constants.CLIENTS.YTMUSIC.NAME; break; case 'ANDROID': ctx.client.clientVersion = Constants.CLIENTS.ANDROID.VERSION; ctx.client.clientFormFactor = 'SMALL_FORM_FACTOR'; ctx.client.clientName = Constants.CLIENTS.ANDROID.NAME; break; case 'YTMUSIC_ANDROID': ctx.client.clientVersion = Constants.CLIENTS.YTMUSIC_ANDROID.VERSION; ctx.client.clientFormFactor = 'SMALL_FORM_FACTOR'; ctx.client.clientName = Constants.CLIENTS.YTMUSIC_ANDROID.NAME; break; case 'YTSTUDIO_ANDROID': ctx.client.clientVersion = Constants.CLIENTS.YTSTUDIO_ANDROID.VERSION; ctx.client.clientFormFactor = 'SMALL_FORM_FACTOR'; ctx.client.clientName = Constants.CLIENTS.YTSTUDIO_ANDROID.NAME; break; case 'TV_EMBEDDED': ctx.client.clientName = Constants.CLIENTS.TV_EMBEDDED.NAME; ctx.client.clientVersion = Constants.CLIENTS.TV_EMBEDDED.VERSION; ctx.client.clientScreen = 'EMBED'; ctx.thirdParty = { embedUrl: Constants.URLS.YT_BASE }; break; case 'YTKIDS': ctx.client.clientVersion = Constants.CLIENTS.WEB_KIDS.VERSION; ctx.client.clientName = Constants.CLIENTS.WEB_KIDS.NAME; ctx.client.kidsAppInfo = { categorySettings: { enabledCategories: [ 'approved_for_you', 'black_joy', 'camp', 'collections', 'earth', 'explore', 'favorites', 'gaming', 'halloween', 'hero', 'learning', 'move', 'music', 'reading', 'shared_by_parents', 'shows', 'soccer', 'sports', 'spotlight', 'winter' ] }, contentSettings: { corpusPreference: 'KIDS_CORPUS_PREFERENCE_YOUNGER', kidsNoSearchMode: 'YT_KIDS_NO_SEARCH_MODE_OFF' } }; break; default: break; } }; export default HTTPClient; //# sourceMappingURL=HTTPClient.js.map