Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions src/Innertube.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Session from './core/Session.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';
Expand All @@ -16,10 +17,10 @@ import {
Search,
VideoInfo
} from './parser/youtube/index.js';

import { ShortFormVideoInfo } from './parser/ytshorts/index.js';

import NavigationEndpoint from './parser/classes/NavigationEndpoint.js';
import type Format from './parser/classes/misc/Format.js';

import * as Constants from './utils/Constants.js';
import { generateRandomString, InnertubeError, throwIfMissing, u8ToBase64 } from './utils/Utils.js';
Expand All @@ -29,12 +30,12 @@ import type {
DownloadOptions,
EngagementType,
FormatOptions,
GetVideoInfoOptions,
InnerTubeClient,
InnerTubeConfig,
SearchFilters
} from './types/index.js';
import type { IBrowseResponse, IParsedResponse } from './parser/index.js';
import type Format from './parser/classes/misc/Format.js';

import {
CommunityPostCommentsParam,
Expand Down Expand Up @@ -70,7 +71,7 @@ export default class Innertube {
return new Innertube(await Session.create(config));
}

async getInfo(target: string | NavigationEndpoint, client?: InnerTubeClient): Promise<VideoInfo> {
async getInfo(target: string | NavigationEndpoint, options: GetVideoInfoOptions): Promise<VideoInfo> {
throwIfMissing({ target });

const payload = {
Expand All @@ -96,10 +97,14 @@ export default class Innertube {
signatureTimestamp: session.player?.sts
}
},
client
client: options?.client
};

if (session.po_token) {
if (options?.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: options.po_token
};
} else if (session.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: session.po_token
};
Expand All @@ -115,7 +120,7 @@ export default class Innertube {
return new VideoInfo(response, session.actions, cpn);
}

async getBasicInfo(video_id: string, client?: InnerTubeClient): Promise<VideoInfo> {
async getBasicInfo(video_id: string, options?: GetVideoInfoOptions): Promise<VideoInfo> {
throwIfMissing({ video_id });

const watch_endpoint = new NavigationEndpoint({
Expand All @@ -137,10 +142,14 @@ export default class Innertube {
signatureTimestamp: session.player?.sts
}
},
client
client: options?.client
};

if (session.po_token) {
if (options?.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: options.po_token
};
} else if (session.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: session.po_token
};
Expand Down Expand Up @@ -445,7 +454,7 @@ export default class Innertube {
* @param options - Format options.
*/
async getStreamingData(video_id: string, options: FormatOptions = {}): Promise<Format> {
const info = await this.getBasicInfo(video_id, options?.client);
const info = await this.getBasicInfo(video_id, options);

const format = info.chooseFormat(options);
format.url = format.decipher(this.#session.player);
Expand All @@ -460,7 +469,7 @@ export default class Innertube {
* @param options - Download options.
*/
async download(video_id: string, options?: DownloadOptions): Promise<ReadableStream<Uint8Array>> {
const info = await this.getBasicInfo(video_id, options?.client);
const info = await this.getBasicInfo(video_id, options);
return info.download(options);
}

Expand Down
8 changes: 4 additions & 4 deletions src/core/Session.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import OAuth2 from './OAuth2.js';
import { Log, EventEmitter, HTTPClient, LZW, ProtoUtils } from '../utils/index.js';
import * as Constants from '../utils/Constants.js';
import Actions from './Actions.js';
import OAuth2 from './OAuth2.js';
import Player from './Player.js';
import * as Constants from '../utils/Constants.js';
import { EventEmitter, HTTPClient, Log, LZW, ProtoUtils } from '../utils/index.js';

import {
generateRandomString, getRandomUserAgent,
Expand Down Expand Up @@ -203,7 +203,7 @@ export type SessionOptions = {
*/
fetch?: FetchFunction;
/**
* Proof of Origin Token. This is an attestation token generated by BotGuard/DroidGuard. It is used to confirm that the request is coming from a genuine client.
* Session bound Proof of Origin Token. This is an attestation token generated by BotGuard/DroidGuard. It is used to confirm that the request is coming from a real client.
*/
po_token?: string;
/**
Expand Down
14 changes: 9 additions & 5 deletions src/core/clients/Kids.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Parser } from '../../parser/index.js';
import { Channel, HomeFeed, Search, VideoInfo } from '../../parser/ytkids/index.js';
import { InnertubeError, generateRandomString } from '../../utils/Utils.js';
import type { Session, ApiResponse } from '../index.js';

import NavigationEndpoint from '../../parser/classes/NavigationEndpoint.js';
import KidsBlocklistPickerItem from '../../parser/classes/ytkids/KidsBlocklistPickerItem.js';
import { InnertubeError, generateRandomString } from '../../utils/Utils.js';
import type { Session, ApiResponse } from '../index.js';
import type { GetVideoInfoOptions } from '../../types/index.js';

export default class Kids {
#session: Session;
Expand All @@ -19,7 +19,7 @@ export default class Kids {
return new Search(this.#session.actions, response);
}

async getInfo(video_id: string): Promise<VideoInfo> {
async getInfo(video_id: string, options?: Omit<GetVideoInfoOptions, 'client'>): Promise<VideoInfo> {
const payload = { videoId: video_id };
const watch_endpoint = new NavigationEndpoint({ watchEndpoint: payload });
const watch_next_endpoint = new NavigationEndpoint({ watchNextEndpoint: payload });
Expand All @@ -38,7 +38,11 @@ export default class Kids {
client: 'YTKIDS'
};

if (session.po_token) {
if (options?.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: options.po_token
};
} else if (session.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: session.po_token
};
Expand Down
31 changes: 20 additions & 11 deletions src/core/clients/Music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import AutomixPreviewVideo from '../../parser/classes/AutomixPreviewVideo.js';
import Message from '../../parser/classes/Message.js';
import MusicDescriptionShelf from '../../parser/classes/MusicDescriptionShelf.js';
import MusicQueue from '../../parser/classes/MusicQueue.js';
import MusicTwoRowItem from '../../parser/classes/MusicTwoRowItem.js';
import MusicResponsiveListItem from '../../parser/classes/MusicResponsiveListItem.js';
import MusicTwoRowItem from '../../parser/classes/MusicTwoRowItem.js';
import NavigationEndpoint from '../../parser/classes/NavigationEndpoint.js';
import PlaylistPanel from '../../parser/classes/PlaylistPanel.js';
import SearchSuggestionsSection from '../../parser/classes/SearchSuggestionsSection.js';
Expand All @@ -27,7 +27,7 @@ import Tab from '../../parser/classes/Tab.js';
import { SearchFilter } from '../../../protos/generated/misc/params.js';

import type { ObservedArray } from '../../parser/helpers.js';
import type { MusicSearchFilters } from '../../types/index.js';
import type { GetVideoInfoOptions, MusicSearchFilters } from '../../types/index.js';
import type { Actions, Session } from '../index.js';

export default class Music {
Expand All @@ -42,19 +42,20 @@ export default class Music {
/**
* Retrieves track info. Passing a list item of type MusicTwoRowItem automatically starts a radio.
* @param target - Video id or a list item.
* @param options - Options for fetching video info.
*/
getInfo(target: string | MusicTwoRowItem | MusicResponsiveListItem | NavigationEndpoint): Promise<TrackInfo> {
getInfo(target: string | MusicTwoRowItem | MusicResponsiveListItem | NavigationEndpoint, options?: Omit<GetVideoInfoOptions, 'client'>): Promise<TrackInfo> {
if (target instanceof MusicTwoRowItem) {
return this.#fetchInfoFromEndpoint(target.endpoint);
return this.#fetchInfoFromEndpoint(target.endpoint, options);
} else if (target instanceof MusicResponsiveListItem) {
return this.#fetchInfoFromEndpoint(target.overlay?.content?.endpoint ?? target.endpoint);
return this.#fetchInfoFromEndpoint(target.overlay?.content?.endpoint ?? target.endpoint, options);
} else if (target instanceof NavigationEndpoint) {
return this.#fetchInfoFromEndpoint(target);
return this.#fetchInfoFromEndpoint(target, options);
}
return this.#fetchInfoFromVideoId(target);
return this.#fetchInfoFromVideoId(target, options);
}

async #fetchInfoFromVideoId(video_id: string): Promise<TrackInfo> {
async #fetchInfoFromVideoId(video_id: string, options?: GetVideoInfoOptions): Promise<TrackInfo> {
const payload = { videoId: video_id, racyCheckOk: true, contentCheckOk: true };
const watch_endpoint = new NavigationEndpoint({ watchEndpoint: payload });
const watch_next_endpoint = new NavigationEndpoint({ watchNextEndpoint: payload });
Expand All @@ -71,7 +72,11 @@ export default class Music {
client: 'YTMUSIC'
};

if (this.#session.po_token) {
if (options?.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: options.po_token
};
} else if (this.#session.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: this.#session.po_token
};
Expand All @@ -87,7 +92,7 @@ export default class Music {
return new TrackInfo(response, this.#actions, cpn);
}

async #fetchInfoFromEndpoint(endpoint?: NavigationEndpoint): Promise<TrackInfo> {
async #fetchInfoFromEndpoint(endpoint?: NavigationEndpoint, options?: GetVideoInfoOptions): Promise<TrackInfo> {
if (!endpoint)
throw new Error('This item does not have an endpoint.');

Expand All @@ -103,7 +108,11 @@ export default class Music {
client: 'YTMUSIC'
};

if (this.#session.po_token) {
if (options?.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: options.po_token
};
} else if (this.#session.po_token) {
extra_payload.serviceIntegrityDimensions = {
poToken: this.#session.po_token
};
Expand Down
8 changes: 2 additions & 6 deletions src/types/FormatUtils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { InnerTubeClient } from '../types/index.js';
import type { GetVideoInfoOptions } from '../types/index.js';
import type { Format } from '../parser/misc.js';

export type URLTransformer = (url: URL) => URL;
export type FormatFilter = (format: Format) => boolean;

export interface FormatOptions {
export interface FormatOptions extends GetVideoInfoOptions {
/**
* Video or audio itag
*/
Expand All @@ -29,10 +29,6 @@ export interface FormatOptions {
* Video or audio codec, e.g. 'avc', 'vp9', 'av01' for video, 'opus', 'mp4a' for audio
*/
codec?: string;
/**
* InnerTube client.
*/
client?: InnerTubeClient;
}

export interface DownloadOptions extends FormatOptions {
Expand Down
13 changes: 13 additions & 0 deletions src/types/GetVideoInfoOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { type InnerTubeClient } from './Misc.js';

export interface GetVideoInfoOptions {
/**
* InnerTube client.
*/
client?: InnerTubeClient;
/**
* Proof of Origin token, bound to the video ID being requested.
* If not provided, session bound token will be used.
*/
po_token?: string;
}
3 changes: 2 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export type { default as PlatformShim } from './PlatformShim.js';
export * from './Cache.js';
export * from './PlatformShim.js';
export * from './Misc.js';
export * from './FormatUtils.js';
export * from './FormatUtils.js';
export * from './GetVideoInfoOptions.js';
Loading