feat: add support for switching accounts (cookie based auth only) (#236)

* feat: add support for switching accounts

* style: lint
This commit is contained in:
LuanRT
2022-11-12 16:26:02 -03:00
committed by GitHub
parent 0130229236
commit 5ea0a0ebf8
7 changed files with 42 additions and 24 deletions

View File

@@ -21,7 +21,7 @@ class AccountManager {
*/
editName: (new_name: string) => {
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
return this.#actions.execute('/channel/edit_name', {
givenName: new_name,
@@ -34,7 +34,7 @@ class AccountManager {
*/
editDescription: (new_description: string) => {
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
return this.#actions.execute('/channel/edit_description', {
givenDescription: new_description,
@@ -53,7 +53,7 @@ class AccountManager {
*/
async getInfo() {
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const response = await this.#actions.execute('/account/accounts_list', { client: 'ANDROID' });
return new AccountInfo(response);

View File

@@ -122,7 +122,7 @@ class Actions {
if (Reflect.has(data, 'browseId')) {
if (this.#needsLogin(data.browseId) && !this.#session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
}
if (Reflect.has(data, 'override_endpoint'))

View File

@@ -17,7 +17,7 @@ class InteractionManager {
throwIfMissing({ video_id });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/like/like', {
client: 'ANDROID',
@@ -37,7 +37,7 @@ class InteractionManager {
throwIfMissing({ video_id });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/like/dislike', {
client: 'ANDROID',
@@ -57,7 +57,7 @@ class InteractionManager {
throwIfMissing({ video_id });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/like/removelike', {
client: 'ANDROID',
@@ -77,7 +77,7 @@ class InteractionManager {
throwIfMissing({ channel_id });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/subscription/subscribe', {
client: 'ANDROID',
@@ -96,7 +96,7 @@ class InteractionManager {
throwIfMissing({ channel_id });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/subscription/unsubscribe', {
client: 'ANDROID',
@@ -116,7 +116,7 @@ class InteractionManager {
throwIfMissing({ video_id, text });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const action = await this.#actions.execute('/comment/create_comment', {
client: 'ANDROID',
@@ -163,7 +163,7 @@ class InteractionManager {
throwIfMissing({ channel_id, type });
if (!this.#actions.session.logged_in)
throw new Error('You are not signed in');
throw new Error('You must be signed in to perform this operation.');
const pref_types = {
PERSONALIZED: 1,

View File

@@ -20,7 +20,7 @@ class PlaylistManager {
throwIfMissing({ title, video_ids });
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const response = await this.#actions.execute('/playlist/create', {
title,
@@ -44,7 +44,7 @@ class PlaylistManager {
throwIfMissing({ playlist_id });
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const response = await this.#actions.execute('playlist/delete', { playlistId: playlist_id });
@@ -65,7 +65,7 @@ class PlaylistManager {
throwIfMissing({ playlist_id, video_ids });
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const response = await this.#actions.execute('/browse/edit_playlist', {
playlistId: playlist_id,
@@ -91,7 +91,7 @@ class PlaylistManager {
throwIfMissing({ playlist_id, video_ids });
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const info = await this.#actions.execute('/browse', {
browseId: `VL${playlist_id}`,
@@ -150,7 +150,7 @@ class PlaylistManager {
throwIfMissing({ playlist_id, moved_video_id, predecessor_video_id });
if (!this.#actions.session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const info = await this.#actions.execute('/browse', {
browseId: `VL${playlist_id}`,

View File

@@ -56,6 +56,7 @@ export interface Context {
export interface SessionOptions {
lang?: string;
account_index?: number;
device_category?: DeviceCategory;
client_type?: ClientType;
timezone?: string;
@@ -68,6 +69,7 @@ export default class Session extends EventEmitterLike {
#api_version;
#key;
#context;
#account_index;
#player;
oauth;
@@ -76,9 +78,10 @@ export default class Session extends EventEmitterLike {
actions;
cache;
constructor(context: Context, api_key: string, api_version: string, player: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
constructor(context: Context, api_key: string, api_version: string, account_index: number, player: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
super();
this.#context = context;
this.#account_index = account_index;
this.#key = api_key;
this.#api_version = api_version;
this.#player = player;
@@ -107,12 +110,20 @@ export default class Session extends EventEmitterLike {
}
static async create(options: SessionOptions = {}) {
const { context, api_key, api_version } = await Session.getSessionData(options.lang, options.device_category, options.client_type, options.timezone, options.fetch);
return new Session(context, api_key, api_version, await Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache);
const { context, api_key, api_version, account_index } = await Session.getSessionData(
options.lang,
options.account_index,
options.device_category,
options.client_type,
options.timezone,
options.fetch
);
return new Session(context, api_key, api_version, account_index, await Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache);
}
static async getSessionData(
lang = 'en-US',
account_index = 0,
device_category: DeviceCategory = 'desktop',
client_name: ClientType = ClientType.WEB,
tz: string = Intl.DateTimeFormat().resolvedOptions().timeZone,
@@ -177,7 +188,7 @@ export default class Session extends EventEmitterLike {
}
};
return { context, api_key, api_version };
return { context, api_key, api_version, account_index };
}
async signIn(credentials?: Credentials): Promise<void> {
@@ -213,7 +224,7 @@ export default class Session extends EventEmitterLike {
async signOut() {
if (!this.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const response = await this.oauth.revokeCredentials();
this.logged_in = false;
@@ -237,6 +248,10 @@ export default class Session extends EventEmitterLike {
return this.#context.client.clientName;
}
get account_index() {
return this.#account_index;
}
get context() {
return this.#context;
}

View File

@@ -52,7 +52,7 @@ class Studio {
*/
async setThumbnail(video_id: string, buffer: Uint8Array): Promise<ApiResponse> {
if (!this.#session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
if (!video_id || !buffer)
throw new MissingParamError('One or more parameters are missing.');
@@ -83,7 +83,7 @@ class Studio {
*/
async updateVideoMetadata(video_id: string, metadata: VideoMetadata) {
if (!this.#session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const payload = Proto.encodeVideoMetadataPayload(video_id, metadata);
@@ -105,7 +105,7 @@ class Studio {
*/
async upload(file: BodyInit, metadata: UploadedVideoMetadata = {}): Promise<ApiResponse> {
if (!this.#session.logged_in)
throw new InnertubeError('You are not signed in');
throw new InnertubeError('You must be signed in to perform this operation.');
const initial_data = await this.#getInitialUploadData();
const upload_result = await this.#uploadVideo(initial_data.upload_url, file);

View File

@@ -103,9 +103,12 @@ export default class HTTPClient {
if (this.#cookie) {
const papisid = getStringBetweenStrings(this.#cookie, 'PAPISID=', ';');
if (papisid) {
request_headers.set('authorization', await generateSidAuth(papisid));
request_headers.set('x-goog-authuser', this.#session.account_index.toString());
}
request_headers.set('cookie', this.#cookie);
}
}