youtubei.js
Advanced tools
Comparing version 9.4.0 to 10.0.0
{ | ||
"name": "youtubei.js", | ||
"version": "9.4.0", | ||
"version": "10.0.0", | ||
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).", | ||
@@ -15,2 +15,5 @@ "type": "module", | ||
], | ||
"react-native": [ | ||
"./dist/src/platform/lib.d.ts" | ||
], | ||
"web.bundle": [ | ||
@@ -36,2 +39,3 @@ "./dist/src/platform/lib.d.ts" | ||
"browser": "./dist/src/platform/web.js", | ||
"react-native": "./dist/src/platform/react-native.js", | ||
"default": "./dist/src/platform/web.js" | ||
@@ -47,2 +51,6 @@ }, | ||
}, | ||
"./react-native": { | ||
"types": "./dist/src/platform/lib.d.ts", | ||
"default": "./dist/src/platform/react-native.js" | ||
}, | ||
"./web.bundle": { | ||
@@ -81,4 +89,5 @@ "types": "./dist/src/platform/lib.d.ts", | ||
"lint:fix": "npx eslint --fix ./src", | ||
"build": "npm run build:parser-map && npm run build:proto && npm run build:esm && npm run bundle:node && npm run bundle:browser && npm run bundle:browser:prod && npm run bundle:cf-worker", | ||
"build:parser-map": "node ./scripts/gen-parser-map.mjs", | ||
"clean": "npx rimraf ./dist/src ./dist/package.json ./bundle/browser.js ./bundle/browser.js.map ./bundle/browser.min.js ./bundle/browser.min.js.map ./bundle/node.cjs ./bundle/node.cjs.map ./bundle/cf-worker.js ./bundle/cf-worker.js.map ./bundle/react-native.js ./bundle/react-native.js.map ./deno", | ||
"build": "npm run clean && npm run build:parser-map && npm run build:proto && npm run build:esm && npm run bundle:node && npm run bundle:browser && npm run bundle:browser:prod && npm run bundle:cf-worker && npm run bundle:react-native", | ||
"build:parser-map": "node ./dev-scripts/gen-parser-map.mjs", | ||
"build:proto": "npx pb-gen-ts --entry-path=\"src/proto\" --out-dir=\"src/proto/generated\" --ext-in-import=\".js\"", | ||
@@ -89,2 +98,3 @@ "build:esm": "npx tspc", | ||
"bundle:browser": "npx esbuild ./dist/src/platform/web.js --banner:js=\"/* eslint-disable */\" --bundle --target=chrome58 --keep-names --format=esm --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/browser.js --platform=browser", | ||
"bundle:react-native": "npx esbuild ./dist/src/platform/react-native.js --bundle --target=es2020 --keep-names --format=esm --platform=neutral --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/react-native.js", | ||
"bundle:browser:prod": "npm run bundle:browser -- --outfile=./bundle/browser.min.js --minify", | ||
@@ -119,6 +129,6 @@ "bundle:cf-worker": "npx esbuild ./dist/src/platform/cf-worker.js --banner:js=\"/* eslint-disable */\" --bundle --target=es2020 --keep-names --format=esm --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/cf-worker.js --platform=node", | ||
"glob": "^8.0.3", | ||
"jest": "^28.1.3", | ||
"jest": "^29.7.0", | ||
"pbkit": "^0.0.59", | ||
"replace": "^1.2.2", | ||
"ts-jest": "^28.0.8", | ||
"ts-jest": "^29.1.4", | ||
"ts-patch": "^3.0.2", | ||
@@ -125,0 +135,0 @@ "ts-transformer-inline-file": "^0.2.0", |
@@ -12,4 +12,4 @@ import type { Session } from './index.js'; | ||
#private; | ||
session: Session; | ||
constructor(session: Session); | ||
get session(): Session; | ||
/** | ||
@@ -16,0 +16,0 @@ * Makes calls to the playback tracking API. |
@@ -1,3 +0,3 @@ | ||
var _Actions_instances, _Actions_session, _Actions_wrap, _Actions_isBrowse, _Actions_needsLogin; | ||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; | ||
var _Actions_instances, _Actions_wrap, _Actions_isBrowse, _Actions_needsLogin; | ||
import { __awaiter, __classPrivateFieldGet } from "tslib"; | ||
import { Parser, NavigateAction } from '../parser/index.js'; | ||
@@ -8,8 +8,4 @@ import { InnertubeError } from '../utils/Utils.js'; | ||
_Actions_instances.add(this); | ||
_Actions_session.set(this, void 0); | ||
__classPrivateFieldSet(this, _Actions_session, session, "f"); | ||
this.session = session; | ||
} | ||
get session() { | ||
return __classPrivateFieldGet(this, _Actions_session, "f"); | ||
} | ||
/** | ||
@@ -31,3 +27,3 @@ * Makes calls to the playback tracking API. | ||
} | ||
const response = yield __classPrivateFieldGet(this, _Actions_session, "f").http.fetch(s_url); | ||
const response = yield this.session.http.fetch(s_url); | ||
return response; | ||
@@ -37,4 +33,4 @@ }); | ||
execute(endpoint, args) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
let data; | ||
@@ -44,3 +40,3 @@ if (args && !args.protobuf) { | ||
if (Reflect.has(data, 'browseId')) { | ||
if (__classPrivateFieldGet(this, _Actions_instances, "m", _Actions_needsLogin).call(this, data.browseId) && !__classPrivateFieldGet(this, _Actions_session, "f").logged_in) | ||
if (__classPrivateFieldGet(this, _Actions_instances, "m", _Actions_needsLogin).call(this, data.browseId) && !this.session.logged_in) | ||
throw new InnertubeError('You must be signed in to perform this operation.'); | ||
@@ -78,3 +74,3 @@ } | ||
const target_endpoint = Reflect.has(args || {}, 'override_endpoint') ? args === null || args === void 0 ? void 0 : args.override_endpoint : endpoint; | ||
const response = yield __classPrivateFieldGet(this, _Actions_session, "f").http.fetch(target_endpoint, { | ||
const response = yield this.session.http.fetch(target_endpoint, { | ||
method: 'POST', | ||
@@ -103,3 +99,3 @@ body: (args === null || args === void 0 ? void 0 : args.protobuf) ? data : JSON.stringify((data || {})), | ||
} | ||
_Actions_session = new WeakMap(), _Actions_instances = new WeakSet(), _Actions_wrap = function _Actions_wrap(response) { | ||
_Actions_instances = new WeakSet(), _Actions_wrap = function _Actions_wrap(response) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -106,0 +102,0 @@ return { |
@@ -29,4 +29,4 @@ var _Kids_session; | ||
getInfo(video_id) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const player_payload = PlayerEndpoint.build({ | ||
@@ -80,4 +80,4 @@ sts: (_a = __classPrivateFieldGet(this, _Kids_session, "f").player) === null || _a === void 0 ? void 0 : _a.sts, | ||
blockChannel(channel_id) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
if (!__classPrivateFieldGet(this, _Kids_session, "f").logged_in) | ||
@@ -84,0 +84,0 @@ throw new InnertubeError('You must be signed in to perform this operation.'); |
@@ -43,4 +43,4 @@ var _Music_instances, _Music_session, _Music_actions, _Music_fetchInfoFromVideoId, _Music_fetchInfoFromListItem; | ||
*/ | ||
search(query, filters = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
search(query_1) { | ||
return __awaiter(this, arguments, void 0, function* (query, filters = {}) { | ||
throwIfMissing({ query }); | ||
@@ -145,5 +145,5 @@ const response = yield __classPrivateFieldGet(this, _Music_actions, "f").execute(SearchEndpoint.PATH, SearchEndpoint.build({ | ||
*/ | ||
getUpNext(video_id, automix = true) { | ||
var _a, _b, _c; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
getUpNext(video_id_1) { | ||
return __awaiter(this, arguments, void 0, function* (video_id, automix = true) { | ||
var _a, _b, _c; | ||
throwIfMissing({ video_id }); | ||
@@ -180,4 +180,4 @@ const response = yield __classPrivateFieldGet(this, _Music_actions, "f").execute(NextEndpoint.PATH, Object.assign(Object.assign({}, NextEndpoint.build({ video_id, client: 'YTMUSIC' })), { parse: true })); | ||
getRelated(video_id) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
throwIfMissing({ video_id }); | ||
@@ -201,4 +201,4 @@ const response = yield __classPrivateFieldGet(this, _Music_actions, "f").execute(NextEndpoint.PATH, Object.assign(Object.assign({}, NextEndpoint.build({ video_id, client: 'YTMUSIC' })), { parse: true })); | ||
getLyrics(video_id) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
throwIfMissing({ video_id }); | ||
@@ -246,4 +246,4 @@ const response = yield __classPrivateFieldGet(this, _Music_actions, "f").execute(NextEndpoint.PATH, Object.assign(Object.assign({}, NextEndpoint.build({ video_id, client: 'YTMUSIC' })), { parse: true })); | ||
_Music_session = new WeakMap(), _Music_actions = new WeakMap(), _Music_instances = new WeakSet(), _Music_fetchInfoFromVideoId = function _Music_fetchInfoFromVideoId(video_id) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const player_payload = PlayerEndpoint.build({ | ||
@@ -265,4 +265,4 @@ video_id, | ||
}, _Music_fetchInfoFromListItem = function _Music_fetchInfoFromListItem(list_item) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!list_item) | ||
@@ -269,0 +269,0 @@ throw new InnertubeError('List item cannot be undefined'); |
@@ -69,4 +69,4 @@ var _Studio_instances, _Studio_session, _Studio_getInitialUploadData, _Studio_uploadVideo, _Studio_setVideoMetadata; | ||
*/ | ||
upload(file, metadata = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
upload(file_1) { | ||
return __awaiter(this, arguments, void 0, function* (file, metadata = {}) { | ||
if (!__classPrivateFieldGet(this, _Studio_session, "f").logged_in) | ||
@@ -73,0 +73,0 @@ throw new InnertubeError('You must be signed in to perform this operation.'); |
@@ -7,4 +7,4 @@ export { default as Session } from './Session.js'; | ||
export * from './Player.js'; | ||
export { default as OAuth } from './OAuth.js'; | ||
export * from './OAuth.js'; | ||
export { default as OAuth2 } from './OAuth2.js'; | ||
export * from './OAuth2.js'; | ||
export * as Clients from './clients/index.js'; | ||
@@ -11,0 +11,0 @@ export * as Endpoints from './endpoints/index.js'; |
@@ -7,4 +7,4 @@ export { default as Session } from './Session.js'; | ||
export * from './Player.js'; | ||
export { default as OAuth } from './OAuth.js'; | ||
export * from './OAuth.js'; | ||
export { default as OAuth2 } from './OAuth2.js'; | ||
export * from './OAuth2.js'; | ||
export * as Clients from './clients/index.js'; | ||
@@ -11,0 +11,0 @@ export * as Endpoints from './endpoints/index.js'; |
@@ -81,4 +81,4 @@ var _AccountManager_actions; | ||
getAnalytics() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const info = yield this.getInfo(); | ||
@@ -85,0 +85,0 @@ const response = yield __classPrivateFieldGet(this, _AccountManager_actions, "f").execute(BrowseEndpoint.PATH, BrowseEndpoint.build({ |
@@ -120,4 +120,4 @@ var _InteractionManager_actions; | ||
*/ | ||
translate(text, target_language, args = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
translate(text_1, target_language_1) { | ||
return __awaiter(this, arguments, void 0, function* (text, target_language, args = {}) { | ||
throwIfMissing({ text, target_language }); | ||
@@ -124,0 +124,0 @@ const target_action = Proto.encodeCommentActionParams(22, Object.assign({ text, target_language }, args)); |
@@ -32,3 +32,3 @@ import { ReloadContinuationItemsCommand } from '../../parser/index.js'; | ||
*/ | ||
static getVideosFromMemo(memo: Memo): ObservedArray<CompactVideo | GridVideo | PlaylistPanelVideo | PlaylistVideo | ReelItem | Video | WatchCardCompactVideo>; | ||
static getVideosFromMemo(memo: Memo): ObservedArray<Video | CompactVideo | GridVideo | PlaylistPanelVideo | PlaylistVideo | ReelItem | WatchCardCompactVideo>; | ||
/** | ||
@@ -41,3 +41,3 @@ * Get all playlists on a given page via memo | ||
*/ | ||
get videos(): ObservedArray<CompactVideo | GridVideo | PlaylistPanelVideo | PlaylistVideo | ReelItem | Video | WatchCardCompactVideo>; | ||
get videos(): ObservedArray<Video | CompactVideo | GridVideo | PlaylistPanelVideo | PlaylistVideo | ReelItem | WatchCardCompactVideo>; | ||
/** | ||
@@ -44,0 +44,0 @@ * Get all the community posts in the feed |
@@ -36,4 +36,4 @@ var _FilterableFeed_chips; | ||
getFilteredFeed(filter) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
let target_filter; | ||
@@ -40,0 +40,0 @@ if (typeof filter === 'string') { |
@@ -35,5 +35,5 @@ var _MediaInfo_page, _MediaInfo_actions, _MediaInfo_cpn, _MediaInfo_playback_tracking; | ||
*/ | ||
toDash(url_transformer, format_filter, options = { include_thumbnails: false }) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
toDash(url_transformer_1, format_filter_1) { | ||
return __awaiter(this, arguments, void 0, function* (url_transformer, format_filter, options = { include_thumbnails: false }) { | ||
var _a; | ||
const player_response = __classPrivateFieldGet(this, _MediaInfo_page, "f")[0]; | ||
@@ -47,3 +47,3 @@ if (player_response.video_details && (player_response.video_details.is_live)) { | ||
} | ||
return FormatUtils.toDash(this.streaming_data, (_a = this.page[0].video_details) === null || _a === void 0 ? void 0 : _a.is_post_live_dvr, url_transformer, format_filter, __classPrivateFieldGet(this, _MediaInfo_cpn, "f"), __classPrivateFieldGet(this, _MediaInfo_actions, "f").session.player, __classPrivateFieldGet(this, _MediaInfo_actions, "f"), storyboards); | ||
return FormatUtils.toDash(this.streaming_data, (_a = this.page[0].video_details) === null || _a === void 0 ? void 0 : _a.is_post_live_dvr, url_transformer, format_filter, __classPrivateFieldGet(this, _MediaInfo_cpn, "f"), __classPrivateFieldGet(this, _MediaInfo_actions, "f").session.player, __classPrivateFieldGet(this, _MediaInfo_actions, "f"), storyboards, options); | ||
}); | ||
@@ -69,4 +69,4 @@ } | ||
*/ | ||
download(options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
download() { | ||
return __awaiter(this, arguments, void 0, function* (options = {}) { | ||
const player_response = __classPrivateFieldGet(this, _MediaInfo_page, "f")[0]; | ||
@@ -84,4 +84,4 @@ if (player_response.video_details && (player_response.video_details.is_live || player_response.video_details.is_post_live_dvr)) { | ||
getTranscript() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const next_response = this.page[1]; | ||
@@ -107,4 +107,4 @@ if (!next_response) | ||
*/ | ||
addToWatchHistory(client_name = Constants.CLIENTS.WEB.NAME, client_version = Constants.CLIENTS.WEB.VERSION, replacement = 'https://www.') { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
addToWatchHistory() { | ||
return __awaiter(this, arguments, void 0, function* (client_name = Constants.CLIENTS.WEB.NAME, client_version = Constants.CLIENTS.WEB.VERSION, replacement = 'https://www.') { | ||
if (!__classPrivateFieldGet(this, _MediaInfo_playback_tracking, "f")) | ||
@@ -111,0 +111,0 @@ throw new InnertubeError('Playback tracking not available'); |
@@ -20,4 +20,4 @@ var _TabbedFeed_tabs, _TabbedFeed_actions; | ||
getTabByName(title) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const tab = (_a = __classPrivateFieldGet(this, _TabbedFeed_tabs, "f")) === null || _a === void 0 ? void 0 : _a.find((tab) => tab.title.toLowerCase() === title.toLowerCase()); | ||
@@ -33,4 +33,4 @@ if (!tab) | ||
getTabByURL(url) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const tab = (_a = __classPrivateFieldGet(this, _TabbedFeed_tabs, "f")) === null || _a === void 0 ? void 0 : _a.find((tab) => { var _a; return ((_a = tab.endpoint.metadata.url) === null || _a === void 0 ? void 0 : _a.split('/').pop()) === url; }); | ||
@@ -37,0 +37,0 @@ if (!tab) |
@@ -6,4 +6,6 @@ import type { ICache, FetchFunction } from '../types/index.js'; | ||
export default class Player { | ||
#private; | ||
static TAG: string; | ||
nsig_sc: string; | ||
sig_sc: string; | ||
sts: number; | ||
player_id: string; | ||
constructor(signature_timestamp: number, sig_sc: string, nsig_sc: string, player_id: string); | ||
@@ -19,6 +21,3 @@ static create(cache: ICache | undefined, fetch?: FetchFunction): Promise<Player>; | ||
get url(): string; | ||
get sts(): number; | ||
get nsig_sc(): string; | ||
get sig_sc(): string; | ||
static get LIBRARY_VERSION(): number; | ||
} |
@@ -1,21 +0,17 @@ | ||
var _Player_nsig_sc, _Player_sig_sc, _Player_sig_sc_timestamp, _Player_player_id; | ||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; | ||
import { Log, Constants } from '../utils/index.js'; | ||
import { __awaiter } from "tslib"; | ||
import { Log, LZW, Constants } from '../utils/index.js'; | ||
import { Platform, getRandomUserAgent, getStringBetweenStrings, PlayerError } from '../utils/Utils.js'; | ||
const TAG = 'Player'; | ||
/** | ||
* Represents YouTube's player script. This is required to decipher signatures. | ||
*/ | ||
class Player { | ||
export default class Player { | ||
constructor(signature_timestamp, sig_sc, nsig_sc, player_id) { | ||
_Player_nsig_sc.set(this, void 0); | ||
_Player_sig_sc.set(this, void 0); | ||
_Player_sig_sc_timestamp.set(this, void 0); | ||
_Player_player_id.set(this, void 0); | ||
__classPrivateFieldSet(this, _Player_nsig_sc, nsig_sc, "f"); | ||
__classPrivateFieldSet(this, _Player_sig_sc, sig_sc, "f"); | ||
__classPrivateFieldSet(this, _Player_sig_sc_timestamp, signature_timestamp, "f"); | ||
__classPrivateFieldSet(this, _Player_player_id, player_id, "f"); | ||
this.nsig_sc = nsig_sc; | ||
this.sig_sc = sig_sc; | ||
this.sts = signature_timestamp; | ||
this.player_id = player_id; | ||
} | ||
static create(cache, fetch = Platform.shim.fetch) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
static create(cache_1) { | ||
return __awaiter(this, arguments, void 0, function* (cache, fetch = Platform.shim.fetch) { | ||
const url = new URL('/iframe_api', Constants.URLS.YT_BASE); | ||
@@ -27,3 +23,3 @@ const res = yield fetch(url); | ||
const player_id = getStringBetweenStrings(js, 'player\\/', '\\/'); | ||
Log.info(Player.TAG, `Got player id (${player_id}). Checking for cached players..`); | ||
Log.info(TAG, `Got player id (${player_id}). Checking for cached players..`); | ||
if (!player_id) | ||
@@ -33,9 +29,10 @@ throw new PlayerError('Failed to get player id'); | ||
if (cache) { | ||
Log.info(Player.TAG, 'Found a cached player.'); | ||
const cached_player = yield Player.fromCache(cache, player_id); | ||
if (cached_player) | ||
if (cached_player) { | ||
Log.info(TAG, 'Found up-to-date player data in cache.'); | ||
return cached_player; | ||
} | ||
} | ||
const player_url = new URL(`/s/player/${player_id}/player_ias.vflset/en_US/base.js`, Constants.URLS.YT_BASE); | ||
Log.info(Player.TAG, `Could not find any cached player. Will download a new player from ${player_url}.`); | ||
Log.info(TAG, `Could not find any cached player. Will download a new player from ${player_url}.`); | ||
const player_res = yield fetch(player_url, { | ||
@@ -53,3 +50,3 @@ headers: { | ||
const nsig_sc = this.extractNSigSourceCode(player_js); | ||
Log.info(Player.TAG, `Got signature timestamp (${sig_timestamp}) and algorithms needed to decipher signatures.`); | ||
Log.info(TAG, `Got signature timestamp (${sig_timestamp}) and algorithms needed to decipher signatures.`); | ||
return yield Player.fromSource(cache, sig_timestamp, sig_sc, nsig_sc, player_id); | ||
@@ -65,6 +62,6 @@ }); | ||
if (signature_cipher || cipher) { | ||
const signature = Platform.shim.eval(__classPrivateFieldGet(this, _Player_sig_sc, "f"), { | ||
const signature = Platform.shim.eval(this.sig_sc, { | ||
sig: args.get('s') | ||
}); | ||
Log.info(Player.TAG, `Transformed signature ${args.get('s')} to ${signature}.`); | ||
Log.info(TAG, `Transformed signature from ${args.get('s')} to ${signature}.`); | ||
if (typeof signature !== 'string') | ||
@@ -84,10 +81,10 @@ throw new PlayerError('Failed to decipher signature'); | ||
else { | ||
nsig = Platform.shim.eval(__classPrivateFieldGet(this, _Player_nsig_sc, "f"), { | ||
nsig = Platform.shim.eval(this.nsig_sc, { | ||
nsig: n | ||
}); | ||
Log.info(Player.TAG, `Transformed nsig ${n} to ${nsig}.`); | ||
Log.info(TAG, `Transformed n signature from ${n} to ${nsig}.`); | ||
if (typeof nsig !== 'string') | ||
throw new PlayerError('Failed to decipher nsig'); | ||
if (nsig.startsWith('enhanced_except_')) { | ||
Log.warn(Player.TAG, 'Could not transform nsig, download may be throttled.\nChanging the InnerTube client to "ANDROID" might help!'); | ||
Log.warn(TAG, 'Could not transform nsig, download may be throttled.'); | ||
} | ||
@@ -122,3 +119,3 @@ else if (this_response_nsig_cache) { | ||
const result = url_components.toString(); | ||
Log.info(Player.TAG, `Full deciphered URL: ${result}`); | ||
Log.info(TAG, `Deciphered URL: ${result}`); | ||
return url_components.toString(); | ||
@@ -139,5 +136,4 @@ } | ||
const nsig_buf = buffer.slice(12 + sig_len); | ||
const decoder = new TextDecoder(); | ||
const sig_sc = decoder.decode(sig_buf); | ||
const nsig_sc = decoder.decode(nsig_buf); | ||
const sig_sc = LZW.decompress(new TextDecoder().decode(sig_buf)); | ||
const nsig_sc = LZW.decompress(new TextDecoder().decode(nsig_buf)); | ||
return new Player(sig_timestamp, sig_sc, nsig_sc, player_id); | ||
@@ -158,12 +154,12 @@ }); | ||
const encoder = new TextEncoder(); | ||
const sig_buf = encoder.encode(__classPrivateFieldGet(this, _Player_sig_sc, "f")); | ||
const nsig_buf = encoder.encode(__classPrivateFieldGet(this, _Player_nsig_sc, "f")); | ||
const sig_buf = encoder.encode(LZW.compress(this.sig_sc)); | ||
const nsig_buf = encoder.encode(LZW.compress(this.nsig_sc)); | ||
const buffer = new ArrayBuffer(12 + sig_buf.byteLength + nsig_buf.byteLength); | ||
const view = new DataView(buffer); | ||
view.setUint32(0, Player.LIBRARY_VERSION, true); | ||
view.setUint32(4, __classPrivateFieldGet(this, _Player_sig_sc_timestamp, "f"), true); | ||
view.setUint32(4, this.sts, true); | ||
view.setUint32(8, sig_buf.byteLength, true); | ||
new Uint8Array(buffer).set(sig_buf, 12); | ||
new Uint8Array(buffer).set(nsig_buf, 12 + sig_buf.byteLength); | ||
yield cache.set(__classPrivateFieldGet(this, _Player_player_id, "f"), new Uint8Array(buffer)); | ||
yield cache.set(this.player_id, new Uint8Array(buffer)); | ||
}); | ||
@@ -180,3 +176,3 @@ } | ||
if (!functions || !calls) | ||
Log.warn(Player.TAG, 'Failed to extract signature decipher algorithm.'); | ||
Log.warn(TAG, 'Failed to extract signature decipher algorithm.'); | ||
return `function descramble_sig(a) { a = a.split(""); let ${obj_name}={${functions}}${calls} return a.join("") } descramble_sig(sig);`; | ||
@@ -187,24 +183,12 @@ } | ||
if (!sc) | ||
Log.warn(Player.TAG, 'Failed to extract n-token decipher algorithm'); | ||
Log.warn(TAG, 'Failed to extract n-token decipher algorithm'); | ||
return sc; | ||
} | ||
get url() { | ||
return new URL(`/s/player/${__classPrivateFieldGet(this, _Player_player_id, "f")}/player_ias.vflset/en_US/base.js`, Constants.URLS.YT_BASE).toString(); | ||
return new URL(`/s/player/${this.player_id}/player_ias.vflset/en_US/base.js`, Constants.URLS.YT_BASE).toString(); | ||
} | ||
get sts() { | ||
return __classPrivateFieldGet(this, _Player_sig_sc_timestamp, "f"); | ||
} | ||
get nsig_sc() { | ||
return __classPrivateFieldGet(this, _Player_nsig_sc, "f"); | ||
} | ||
get sig_sc() { | ||
return __classPrivateFieldGet(this, _Player_sig_sc, "f"); | ||
} | ||
static get LIBRARY_VERSION() { | ||
return 2; | ||
return 10; | ||
} | ||
} | ||
_Player_nsig_sc = new WeakMap(), _Player_sig_sc = new WeakMap(), _Player_sig_sc_timestamp = new WeakMap(), _Player_player_id = new WeakMap(); | ||
Player.TAG = 'Player'; | ||
export default Player; | ||
//# sourceMappingURL=Player.js.map |
@@ -1,2 +0,2 @@ | ||
import OAuth from './OAuth.js'; | ||
import OAuth2 from './OAuth2.js'; | ||
import { EventEmitter, HTTPClient } from '../utils/index.js'; | ||
@@ -7,3 +7,3 @@ import Actions from './Actions.js'; | ||
import type { FetchFunction, ICache } from '../types/index.js'; | ||
import type { Credentials, OAuthAuthErrorEventHandler, OAuthAuthEventHandler, OAuthAuthPendingEventHandler } from './OAuth.js'; | ||
import type { OAuth2Tokens, OAuth2AuthErrorEventHandler, OAuth2AuthPendingEventHandler, OAuth2AuthEventHandler } from './OAuth2.js'; | ||
export declare enum ClientType { | ||
@@ -19,3 +19,3 @@ WEB = "WEB", | ||
} | ||
export interface Context { | ||
export type Context = { | ||
client: { | ||
@@ -47,2 +47,9 @@ hl: string; | ||
utcOffsetMinutes: number; | ||
mainAppWebInfo?: { | ||
graftUrl: string; | ||
pwaInstallabilityStatus: string; | ||
webDisplayMode: string; | ||
isWebNativeShareAvailable: boolean; | ||
}; | ||
memoryTotalKbytes?: string; | ||
kidsAppInfo?: { | ||
@@ -70,4 +77,22 @@ categorySettings: { | ||
}; | ||
} | ||
export interface SessionOptions { | ||
}; | ||
type ContextData = { | ||
hl: string; | ||
gl: string; | ||
remote_host?: string; | ||
visitor_data: string; | ||
client_name: string; | ||
client_version: string; | ||
os_name: string; | ||
os_version: string; | ||
device_category: string; | ||
time_zone: string; | ||
enable_safety_mode: boolean; | ||
browser_name?: string; | ||
browser_version?: string; | ||
device_make: string; | ||
device_model: string; | ||
on_behalf_of_user?: string; | ||
}; | ||
export type SessionOptions = { | ||
/** | ||
@@ -83,4 +108,4 @@ * Language. | ||
* The account index to use. This is useful if you have multiple accounts logged in. | ||
* **NOTE:** | ||
* Only works if you are signed in with cookies. | ||
* | ||
* **NOTE:** Only works if you are signed in with cookies. | ||
*/ | ||
@@ -94,2 +119,3 @@ account_index?: number; | ||
* Specifies whether to retrieve the JS player. Disabling this will make session creation faster. | ||
* | ||
* **NOTE:** Deciphering formats is not possible without the JS player. | ||
@@ -105,5 +131,12 @@ */ | ||
* This can be useful if you need more performance. | ||
* | ||
* **NOTE:** If you are using the cache option and a session has already been generated, this will be ignored. | ||
* If you want to force a new session to be generated, you must clear the cache or disable session caching. | ||
*/ | ||
generate_session_locally?: boolean; | ||
/** | ||
* Specifies whether the session data should be cached. | ||
*/ | ||
enable_session_cache?: boolean; | ||
/** | ||
* Platform to use for the session. | ||
@@ -121,3 +154,3 @@ */ | ||
/** | ||
* Used to cache the deciphering functions from the JS player. | ||
* Used to cache algorithms, session data, and OAuth2 tokens. | ||
*/ | ||
@@ -138,8 +171,13 @@ cache?: ICache; | ||
fetch?: FetchFunction; | ||
} | ||
export interface SessionData { | ||
}; | ||
export type SessionData = { | ||
context: Context; | ||
api_key: string; | ||
api_version: string; | ||
} | ||
}; | ||
export type SWSessionData = { | ||
context_data: ContextData; | ||
api_key: string; | ||
api_version: string; | ||
}; | ||
export type SessionArgs = { | ||
@@ -160,4 +198,5 @@ lang: string; | ||
#private; | ||
static TAG: string; | ||
oauth: OAuth; | ||
context: Context; | ||
player?: Player; | ||
oauth: OAuth2; | ||
http: HTTPClient; | ||
@@ -167,12 +206,21 @@ logged_in: boolean; | ||
cache?: ICache; | ||
key: string; | ||
api_version: string; | ||
account_index: number; | ||
constructor(context: Context, api_key: string, api_version: string, account_index: number, player?: Player, cookie?: string, fetch?: FetchFunction, cache?: ICache); | ||
on(type: 'auth', listener: OAuthAuthEventHandler): void; | ||
on(type: 'auth-pending', listener: OAuthAuthPendingEventHandler): void; | ||
on(type: 'auth-error', listener: OAuthAuthErrorEventHandler): void; | ||
on(type: 'update-credentials', listener: OAuthAuthEventHandler): void; | ||
once(type: 'auth', listener: OAuthAuthEventHandler): void; | ||
once(type: 'auth-pending', listener: OAuthAuthPendingEventHandler): void; | ||
once(type: 'auth-error', listener: OAuthAuthErrorEventHandler): void; | ||
on(type: 'auth', listener: OAuth2AuthEventHandler): void; | ||
on(type: 'auth-pending', listener: OAuth2AuthPendingEventHandler): void; | ||
on(type: 'auth-error', listener: OAuth2AuthErrorEventHandler): void; | ||
on(type: 'update-credentials', listener: OAuth2AuthEventHandler): void; | ||
once(type: 'auth', listener: OAuth2AuthEventHandler): void; | ||
once(type: 'auth-pending', listener: OAuth2AuthPendingEventHandler): void; | ||
once(type: 'auth-error', listener: OAuth2AuthErrorEventHandler): void; | ||
static create(options?: SessionOptions): Promise<Session>; | ||
static getSessionData(lang?: string, location?: string, account_index?: number, visitor_data?: string, enable_safety_mode?: boolean, generate_session_locally?: boolean, device_category?: DeviceCategory, client_name?: ClientType, tz?: string, fetch?: FetchFunction, on_behalf_of_user?: string): Promise<{ | ||
/** | ||
* Retrieves session data from cache. | ||
* @param cache - A valid cache implementation. | ||
* @param session_args - User provided session arguments. | ||
*/ | ||
static fromCache(cache: ICache, session_args: SessionArgs): Promise<SessionData | null>; | ||
static getSessionData(lang?: string, location?: string, account_index?: number, visitor_data?: string, enable_safety_mode?: boolean, generate_session_locally?: boolean, device_category?: DeviceCategory, client_name?: ClientType, tz?: string, fetch?: FetchFunction, on_behalf_of_user?: string, cache?: ICache, enable_session_cache?: boolean): Promise<{ | ||
account_index: number; | ||
@@ -183,3 +231,3 @@ context: Context; | ||
}>; | ||
signIn(credentials?: Credentials): Promise<void>; | ||
signIn(credentials?: OAuth2Tokens): Promise<void>; | ||
/** | ||
@@ -189,16 +237,6 @@ * Signs out of the current account and revokes the credentials. | ||
signOut(): Promise<Response | undefined>; | ||
/** | ||
* InnerTube API key. | ||
*/ | ||
get key(): string; | ||
/** | ||
* InnerTube API version. | ||
*/ | ||
get api_version(): string; | ||
get client_version(): string; | ||
get client_name(): string; | ||
get account_index(): number; | ||
get context(): Context; | ||
get player(): Player | undefined; | ||
get lang(): string; | ||
} | ||
export {}; |
@@ -1,5 +0,5 @@ | ||
var _a, _Session_api_version, _Session_key, _Session_context, _Session_account_index, _Session_player, _Session_getVisitorID, _Session_retrieveSessionData, _Session_generateSessionData; | ||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; | ||
import OAuth from './OAuth.js'; | ||
import { Log, EventEmitter, HTTPClient } from '../utils/index.js'; | ||
var _a, _Session_storeSession, _Session_getSessionData, _Session_buildContext, _Session_getVisitorID; | ||
import { __awaiter, __classPrivateFieldGet } from "tslib"; | ||
import OAuth2 from './OAuth2.js'; | ||
import { Log, EventEmitter, HTTPClient, LZW } from '../utils/index.js'; | ||
import * as Constants from '../utils/Constants.js'; | ||
@@ -21,2 +21,3 @@ import * as Proto from '../proto/index.js'; | ||
})(ClientType || (ClientType = {})); | ||
const TAG = 'Session'; | ||
/** | ||
@@ -28,17 +29,12 @@ * Represents an InnerTube session. This holds all the data needed to make requests to YouTube. | ||
super(); | ||
_Session_api_version.set(this, void 0); | ||
_Session_key.set(this, void 0); | ||
_Session_context.set(this, void 0); | ||
_Session_account_index.set(this, void 0); | ||
_Session_player.set(this, void 0); | ||
__classPrivateFieldSet(this, _Session_context, context, "f"); | ||
__classPrivateFieldSet(this, _Session_account_index, account_index, "f"); | ||
__classPrivateFieldSet(this, _Session_key, api_key, "f"); | ||
__classPrivateFieldSet(this, _Session_api_version, api_version, "f"); | ||
__classPrivateFieldSet(this, _Session_player, player, "f"); | ||
this.http = new HTTPClient(this, cookie, fetch); | ||
this.actions = new Actions(this); | ||
this.oauth = new OAuth(this); | ||
this.oauth = new OAuth2(this); | ||
this.logged_in = !!cookie; | ||
this.cache = cache; | ||
this.account_index = account_index; | ||
this.key = api_key; | ||
this.api_version = api_version; | ||
this.context = context; | ||
this.player = player; | ||
} | ||
@@ -51,27 +47,94 @@ on(type, listener) { | ||
} | ||
static create(options = {}) { | ||
static create() { | ||
return __awaiter(this, arguments, void 0, function* (options = {}) { | ||
const { context, api_key, api_version, account_index } = yield _a.getSessionData(options.lang, options.location, options.account_index, options.visitor_data, options.enable_safety_mode, options.generate_session_locally, options.device_category, options.client_type, options.timezone, options.fetch, options.on_behalf_of_user, options.cache, options.enable_session_cache); | ||
return new _a(context, api_key, api_version, account_index, options.retrieve_player === false ? undefined : yield Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache); | ||
}); | ||
} | ||
/** | ||
* Retrieves session data from cache. | ||
* @param cache - A valid cache implementation. | ||
* @param session_args - User provided session arguments. | ||
*/ | ||
static fromCache(cache, session_args) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { context, api_key, api_version, account_index } = yield Session.getSessionData(options.lang, options.location, options.account_index, options.visitor_data, options.enable_safety_mode, options.generate_session_locally, options.device_category, options.client_type, options.timezone, options.fetch, options.on_behalf_of_user); | ||
return new Session(context, api_key, api_version, account_index, options.retrieve_player === false ? undefined : yield Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache); | ||
const buffer = yield cache.get('innertube_session_data'); | ||
if (!buffer) | ||
return null; | ||
const data = new TextDecoder().decode(buffer.slice(4)); | ||
try { | ||
const result = JSON.parse(LZW.decompress(data)); | ||
if (session_args.visitor_data) { | ||
result.context.client.visitorData = session_args.visitor_data; | ||
} | ||
if (session_args.lang) | ||
result.context.client.hl = session_args.lang; | ||
if (session_args.location) | ||
result.context.client.gl = session_args.location; | ||
if (session_args.on_behalf_of_user) | ||
result.context.user.onBehalfOfUser = session_args.on_behalf_of_user; | ||
result.context.client.timeZone = session_args.time_zone; | ||
result.context.client.platform = session_args.device_category.toUpperCase(); | ||
result.context.client.clientName = session_args.client_name; | ||
result.context.user.enableSafetyMode = session_args.enable_safety_mode; | ||
return result; | ||
} | ||
catch (error) { | ||
Log.error(TAG, 'Failed to parse session data from cache.', error); | ||
return null; | ||
} | ||
}); | ||
} | ||
static getSessionData(lang = '', location = '', account_index = 0, visitor_data = '', enable_safety_mode = false, generate_session_locally = false, device_category = 'desktop', client_name = ClientType.WEB, tz = Intl.DateTimeFormat().resolvedOptions().timeZone, fetch = Platform.shim.fetch, on_behalf_of_user) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
static getSessionData() { | ||
return __awaiter(this, arguments, void 0, function* (lang = '', location = '', account_index = 0, visitor_data = '', enable_safety_mode = false, generate_session_locally = false, device_category = 'desktop', client_name = ClientType.WEB, tz = Intl.DateTimeFormat().resolvedOptions().timeZone, fetch = Platform.shim.fetch, on_behalf_of_user, cache, enable_session_cache = true) { | ||
const session_args = { lang, location, time_zone: tz, device_category, client_name, enable_safety_mode, visitor_data, on_behalf_of_user }; | ||
let session_data; | ||
const session_args = { lang, location, time_zone: tz, device_category, client_name, enable_safety_mode, visitor_data, on_behalf_of_user }; | ||
Log.info(Session.TAG, 'Retrieving InnerTube session.'); | ||
if (generate_session_locally) { | ||
session_data = __classPrivateFieldGet(this, _a, "m", _Session_generateSessionData).call(this, session_args); | ||
if (cache && enable_session_cache) { | ||
const cached_session_data = yield this.fromCache(cache, session_args); | ||
if (cached_session_data) { | ||
Log.info(TAG, 'Found session data in cache.'); | ||
session_data = cached_session_data; | ||
} | ||
} | ||
else { | ||
try { | ||
// This can fail if the data changes or the request is blocked for some reason. | ||
session_data = yield __classPrivateFieldGet(this, _a, "m", _Session_retrieveSessionData).call(this, session_args, fetch); | ||
if (!session_data) { | ||
Log.info(TAG, 'Generating session data.'); | ||
let api_key = Constants.CLIENTS.WEB.API_KEY; | ||
let api_version = Constants.CLIENTS.WEB.API_VERSION; | ||
let context_data = { | ||
hl: lang || 'en', | ||
gl: location || 'US', | ||
remote_host: '', | ||
visitor_data: visitor_data || Proto.encodeVisitorData(generateRandomString(11), Math.floor(Date.now() / 1000)), | ||
client_name: client_name, | ||
client_version: Constants.CLIENTS.WEB.VERSION, | ||
device_category: device_category.toUpperCase(), | ||
os_name: 'Windows', | ||
os_version: '10.0', | ||
time_zone: tz, | ||
browser_name: 'Chrome', | ||
browser_version: '125.0.0.0', | ||
device_make: '', | ||
device_model: '', | ||
enable_safety_mode: enable_safety_mode | ||
}; | ||
if (!generate_session_locally) { | ||
try { | ||
const sw_session_data = yield __classPrivateFieldGet(this, _a, "m", _Session_getSessionData).call(this, session_args, fetch); | ||
api_key = sw_session_data.api_key; | ||
api_version = sw_session_data.api_version; | ||
context_data = sw_session_data.context_data; | ||
} | ||
catch (error) { | ||
Log.error(TAG, 'Failed to retrieve session data from server. Session data generated locally will be used instead.', error); | ||
} | ||
} | ||
catch (err) { | ||
Log.error(Session.TAG, 'Failed to retrieve session data from server. Will try to generate it locally.'); | ||
session_data = __classPrivateFieldGet(this, _a, "m", _Session_generateSessionData).call(this, session_args); | ||
} | ||
session_data = { | ||
api_key, | ||
api_version, | ||
context: __classPrivateFieldGet(this, _a, "m", _Session_buildContext).call(this, context_data) | ||
}; | ||
if (enable_session_cache) | ||
yield __classPrivateFieldGet(this, _a, "m", _Session_storeSession).call(this, session_data, cache); | ||
} | ||
Log.info(Session.TAG, 'Got session data.\n', session_data); | ||
Log.debug(TAG, 'Session data:', session_data); | ||
return Object.assign(Object.assign({}, session_data), { account_index }); | ||
@@ -84,18 +147,10 @@ }); | ||
const error_handler = (err) => reject(err); | ||
this.once('auth', (data) => { | ||
this.once('auth-error', error_handler); | ||
this.once('auth', () => { | ||
this.off('auth-error', error_handler); | ||
if (data.status === 'SUCCESS') { | ||
this.logged_in = true; | ||
resolve(); | ||
} | ||
reject(data); | ||
this.logged_in = true; | ||
resolve(); | ||
}); | ||
this.once('auth-error', error_handler); | ||
try { | ||
yield this.oauth.init(credentials); | ||
if (this.oauth.validateCredentials()) { | ||
yield this.oauth.refreshIfRequired(); | ||
this.logged_in = true; | ||
resolve(); | ||
} | ||
} | ||
@@ -120,51 +175,36 @@ catch (err) { | ||
} | ||
/** | ||
* InnerTube API key. | ||
*/ | ||
get key() { | ||
return __classPrivateFieldGet(this, _Session_key, "f"); | ||
} | ||
/** | ||
* InnerTube API version. | ||
*/ | ||
get api_version() { | ||
return __classPrivateFieldGet(this, _Session_api_version, "f"); | ||
} | ||
get client_version() { | ||
return __classPrivateFieldGet(this, _Session_context, "f").client.clientVersion; | ||
return this.context.client.clientVersion; | ||
} | ||
get client_name() { | ||
return __classPrivateFieldGet(this, _Session_context, "f").client.clientName; | ||
return this.context.client.clientName; | ||
} | ||
get account_index() { | ||
return __classPrivateFieldGet(this, _Session_account_index, "f"); | ||
} | ||
get context() { | ||
return __classPrivateFieldGet(this, _Session_context, "f"); | ||
} | ||
get player() { | ||
return __classPrivateFieldGet(this, _Session_player, "f"); | ||
} | ||
get lang() { | ||
return __classPrivateFieldGet(this, _Session_context, "f").client.hl; | ||
return this.context.client.hl; | ||
} | ||
} | ||
_a = Session, _Session_api_version = new WeakMap(), _Session_key = new WeakMap(), _Session_context = new WeakMap(), _Session_account_index = new WeakMap(), _Session_player = new WeakMap(), _Session_getVisitorID = function _Session_getVisitorID(visitor_data) { | ||
const decoded_visitor_data = Proto.decodeVisitorData(visitor_data); | ||
Log.info(Session.TAG, 'Custom visitor data decoded successfully.\n', decoded_visitor_data); | ||
return decoded_visitor_data.id; | ||
}, _Session_retrieveSessionData = function _Session_retrieveSessionData(options, fetch = Platform.shim.fetch) { | ||
_a = Session, _Session_storeSession = function _Session_storeSession(session_data, cache) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const url = new URL('/sw.js_data', Constants.URLS.YT_BASE); | ||
if (!cache) | ||
return; | ||
Log.info(TAG, 'Compressing and caching session data.'); | ||
const compressed_session_data = new TextEncoder().encode(LZW.compress(JSON.stringify(session_data))); | ||
const buffer = new ArrayBuffer(4 + compressed_session_data.byteLength); | ||
new DataView(buffer).setUint32(0, compressed_session_data.byteLength, true); // (Luan) XX: Leave this here for debugging purposes | ||
new Uint8Array(buffer).set(compressed_session_data, 4); | ||
yield cache.set('innertube_session_data', new Uint8Array(buffer)); | ||
}); | ||
}, _Session_getSessionData = function _Session_getSessionData(options_1) { | ||
return __awaiter(this, arguments, void 0, function* (options, fetch = Platform.shim.fetch) { | ||
let visitor_id = generateRandomString(11); | ||
if (options.visitor_data) { | ||
if (options.visitor_data) | ||
visitor_id = __classPrivateFieldGet(this, _a, "m", _Session_getVisitorID).call(this, options.visitor_data); | ||
} | ||
const url = new URL('/sw.js_data', Constants.URLS.YT_BASE); | ||
const res = yield fetch(url, { | ||
headers: { | ||
'accept-language': options.lang || 'en-US', | ||
'user-agent': getRandomUserAgent('desktop'), | ||
'accept': '*/*', | ||
'referer': 'https://www.youtube.com/sw.js', | ||
'cookie': `PREF=tz=${options.time_zone.replace('/', '.')};VISITOR_INFO1_LIVE=${visitor_id};` | ||
'Accept-Language': options.lang || 'en-US', | ||
'User-Agent': getRandomUserAgent('desktop'), | ||
'Accept': '*/*', | ||
'Referer': `${Constants.URLS.YT_BASE}/sw.js`, | ||
'Cookie': `PREF=tz=${options.time_zone.replace('/', '.')};VISITOR_INFO1_LIVE=${visitor_id};` | ||
} | ||
@@ -175,2 +215,4 @@ }); | ||
const text = yield res.text(); | ||
if (!text.startsWith(')]}\'')) | ||
throw new SessionError('Invalid JSPB response'); | ||
const data = JSON.parse(text.replace(/^\)\]\}'/, '')); | ||
@@ -180,69 +222,56 @@ const ytcfg = data[0][2]; | ||
const [[device_info], api_key] = ytcfg; | ||
const context = { | ||
client: { | ||
hl: device_info[0], | ||
gl: options.location || device_info[2], | ||
remoteHost: device_info[3], | ||
screenDensityFloat: 1, | ||
screenHeightPoints: 1080, | ||
screenPixelDensity: 1, | ||
screenWidthPoints: 1920, | ||
visitorData: device_info[13], | ||
clientName: options.client_name, | ||
clientVersion: device_info[16], | ||
osName: device_info[17], | ||
osVersion: device_info[18], | ||
platform: options.device_category.toUpperCase(), | ||
clientFormFactor: 'UNKNOWN_FORM_FACTOR', | ||
userInterfaceTheme: 'USER_INTERFACE_THEME_LIGHT', | ||
timeZone: device_info[79] || options.time_zone, | ||
browserName: device_info[86], | ||
browserVersion: device_info[87], | ||
originalUrl: Constants.URLS.YT_BASE, | ||
deviceMake: device_info[11], | ||
deviceModel: device_info[12], | ||
utcOffsetMinutes: -new Date().getTimezoneOffset() | ||
}, | ||
user: { | ||
enableSafetyMode: options.enable_safety_mode, | ||
lockedSafetyMode: false | ||
}, | ||
request: { | ||
useSsl: true, | ||
internalExperimentFlags: [] | ||
} | ||
const context_info = { | ||
hl: options.lang || device_info[0], | ||
gl: options.location || device_info[2], | ||
remote_host: device_info[3], | ||
visitor_data: device_info[13], | ||
client_name: options.client_name, | ||
client_version: device_info[16], | ||
os_name: device_info[17], | ||
os_version: device_info[18], | ||
time_zone: device_info[79] || options.time_zone, | ||
device_category: options.device_category, | ||
browser_name: device_info[86], | ||
browser_version: device_info[87], | ||
device_make: device_info[11], | ||
device_model: device_info[12], | ||
enable_safety_mode: options.enable_safety_mode | ||
}; | ||
if (options.on_behalf_of_user) | ||
context.user.onBehalfOfUser = options.on_behalf_of_user; | ||
return { context, api_key, api_version }; | ||
return { context_data: context_info, api_key, api_version }; | ||
}); | ||
}, _Session_generateSessionData = function _Session_generateSessionData(options) { | ||
let visitor_id = generateRandomString(11); | ||
if (options.visitor_data) { | ||
visitor_id = __classPrivateFieldGet(this, _a, "m", _Session_getVisitorID).call(this, options.visitor_data); | ||
} | ||
}, _Session_buildContext = function _Session_buildContext(args) { | ||
const context = { | ||
client: { | ||
hl: options.lang || 'en', | ||
gl: options.location || 'US', | ||
hl: args.hl, | ||
gl: args.gl, | ||
remoteHost: args.remote_host, | ||
screenDensityFloat: 1, | ||
screenHeightPoints: 1080, | ||
screenHeightPoints: 1440, | ||
screenPixelDensity: 1, | ||
screenWidthPoints: 1920, | ||
visitorData: Proto.encodeVisitorData(visitor_id, Math.floor(Date.now() / 1000)), | ||
clientName: options.client_name, | ||
clientVersion: Constants.CLIENTS.WEB.VERSION, | ||
osName: 'Windows', | ||
osVersion: '10.0', | ||
platform: options.device_category.toUpperCase(), | ||
screenWidthPoints: 2560, | ||
visitorData: args.visitor_data, | ||
clientName: args.client_name, | ||
clientVersion: args.client_version, | ||
osName: args.os_name, | ||
osVersion: args.os_version, | ||
platform: args.device_category.toUpperCase(), | ||
clientFormFactor: 'UNKNOWN_FORM_FACTOR', | ||
userInterfaceTheme: 'USER_INTERFACE_THEME_LIGHT', | ||
timeZone: options.time_zone, | ||
timeZone: args.time_zone, | ||
originalUrl: Constants.URLS.YT_BASE, | ||
deviceMake: '', | ||
deviceModel: '', | ||
utcOffsetMinutes: -new Date().getTimezoneOffset() | ||
deviceMake: args.device_make, | ||
deviceModel: args.device_model, | ||
browserName: args.browser_name, | ||
browserVersion: args.browser_version, | ||
utcOffsetMinutes: -new Date().getTimezoneOffset(), | ||
memoryTotalKbytes: '8000000', | ||
mainAppWebInfo: { | ||
graftUrl: Constants.URLS.YT_BASE, | ||
pwaInstallabilityStatus: 'PWA_INSTALLABILITY_STATUS_UNKNOWN', | ||
webDisplayMode: 'WEB_DISPLAY_MODE_BROWSER', | ||
isWebNativeShareAvailable: true | ||
} | ||
}, | ||
user: { | ||
enableSafetyMode: options.enable_safety_mode, | ||
enableSafetyMode: args.enable_safety_mode, | ||
lockedSafetyMode: false | ||
@@ -255,8 +284,10 @@ }, | ||
}; | ||
if (options.on_behalf_of_user) | ||
context.user.onBehalfOfUser = options.on_behalf_of_user; | ||
return { context, api_key: Constants.CLIENTS.WEB.API_KEY, api_version: Constants.CLIENTS.WEB.API_VERSION }; | ||
if (args.on_behalf_of_user) | ||
context.user.onBehalfOfUser = args.on_behalf_of_user; | ||
return context; | ||
}, _Session_getVisitorID = function _Session_getVisitorID(visitor_data) { | ||
const decoded_visitor_data = Proto.decodeVisitorData(visitor_data); | ||
return decoded_visitor_data.id; | ||
}; | ||
Session.TAG = 'Session'; | ||
export default Session; | ||
//# sourceMappingURL=Session.js.map |
@@ -109,3 +109,3 @@ import Session from './core/Session.js'; | ||
*/ | ||
getPlaylists(): Promise<import("./parser/helpers.js").ObservedArray<import("./parser/nodes.js").GridPlaylist | import("./parser/nodes.js").LockupView | import("./parser/nodes.js").Playlist>>; | ||
getPlaylists(): Promise<Feed<IBrowseResponse>>; | ||
/** | ||
@@ -112,0 +112,0 @@ * Retrieves playlist contents. |
@@ -22,4 +22,4 @@ var _Innertube_session; | ||
} | ||
static create(config = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
static create() { | ||
return __awaiter(this, arguments, void 0, function* (config = {}) { | ||
return new Innertube(yield Session.create(config)); | ||
@@ -34,4 +34,4 @@ }); | ||
getInfo(target, client) { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
throwIfMissing({ target }); | ||
@@ -76,4 +76,4 @@ let next_payload; | ||
getBasicInfo(video_id, client) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
throwIfMissing({ video_id }); | ||
@@ -113,4 +113,4 @@ const response = yield this.actions.execute(PlayerEndpoint.PATH, PlayerEndpoint.build({ | ||
*/ | ||
search(query, filters = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
search(query_1) { | ||
return __awaiter(this, arguments, void 0, function* (query, filters = {}) { | ||
throwIfMissing({ query }); | ||
@@ -251,4 +251,4 @@ const response = yield this.actions.execute(SearchEndpoint.PATH, SearchEndpoint.build({ | ||
getUnseenNotificationsCount() { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
const response = yield this.actions.execute(Notification.GetUnseenCountEndpoint.PATH); | ||
@@ -265,4 +265,3 @@ // TODO: properly parse this | ||
const response = yield this.actions.execute(BrowseEndpoint.PATH, Object.assign(Object.assign({}, BrowseEndpoint.build({ browse_id: 'FEplaylist_aggregation' })), { parse: true })); | ||
const feed = new Feed(this.actions, response); | ||
return feed.playlists; | ||
return new Feed(this.actions, response); | ||
}); | ||
@@ -306,4 +305,4 @@ } | ||
*/ | ||
getStreamingData(video_id, options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
getStreamingData(video_id_1) { | ||
return __awaiter(this, arguments, void 0, function* (video_id, options = {}) { | ||
const info = yield this.getBasicInfo(video_id); | ||
@@ -310,0 +309,0 @@ return info.chooseFormat(options); |
@@ -11,3 +11,3 @@ import { YTNode } from '../helpers.js'; | ||
is_full_width: boolean; | ||
type: string; | ||
button_type: string; | ||
button_size: string; | ||
@@ -14,0 +14,0 @@ on_tap: NavigationEndpoint; |
@@ -11,3 +11,3 @@ import { YTNode } from '../helpers.js'; | ||
this.is_full_width = data.isFullWidth; | ||
this.type = data.type; | ||
this.button_type = data.type; | ||
this.button_size = data.buttonSize; | ||
@@ -14,0 +14,0 @@ this.on_tap = new NavigationEndpoint(data.onTap); |
@@ -47,4 +47,4 @@ var _Comment_actions; | ||
like() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!__classPrivateFieldGet(this, _Comment_actions, "f")) | ||
@@ -65,4 +65,4 @@ throw new InnertubeError('An active caller must be provide to perform this operation.'); | ||
dislike() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!__classPrivateFieldGet(this, _Comment_actions, "f")) | ||
@@ -83,4 +83,4 @@ throw new InnertubeError('An active caller must be provide to perform this operation.'); | ||
reply(text) { | ||
var _a, _b, _c; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c; | ||
if (!__classPrivateFieldGet(this, _Comment_actions, "f")) | ||
@@ -108,4 +108,4 @@ throw new InnertubeError('An active caller must be provide to perform this operation.'); | ||
translate(target_language) { | ||
var _a, _b, _c, _d, _e, _f; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e, _f; | ||
if (!__classPrivateFieldGet(this, _Comment_actions, "f")) | ||
@@ -112,0 +112,0 @@ throw new InnertubeError('An active caller must be provide to perform this operation.'); |
@@ -30,4 +30,4 @@ var _CommentThread_actions, _CommentThread_continuation; | ||
getReplies() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!__classPrivateFieldGet(this, _CommentThread_actions, "f")) | ||
@@ -55,4 +55,4 @@ throw new InnertubeError('Actions instance not set for this thread.'); | ||
getContinuation() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!this.replies) | ||
@@ -59,0 +59,0 @@ throw new InnertubeError('Cannot retrieve continuation because this thread\'s replies have not been loaded.'); |
@@ -127,4 +127,4 @@ var _CommentView_actions; | ||
reply(comment_text) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!__classPrivateFieldGet(this, _CommentView_actions, "f")) | ||
@@ -152,4 +152,4 @@ throw new InnertubeError('Actions instance not set for this comment.'); | ||
translate(target_language) { | ||
var _a, _b, _c, _d, _e, _f; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e, _f; | ||
if (!__classPrivateFieldGet(this, _CommentView_actions, "f")) | ||
@@ -156,0 +156,0 @@ throw new InnertubeError('Actions instance not set for this comment.'); |
import { type ObservedArray, YTNode } from '../helpers.js'; | ||
import { type RawNode } from '../index.js'; | ||
import ButtonView from './ButtonView.js'; | ||
import ToggleButtonView from './ToggleButtonView.js'; | ||
export type ActionRow = { | ||
actions: ObservedArray<ButtonView>; | ||
actions: ObservedArray<ButtonView | ToggleButtonView>; | ||
}; | ||
@@ -7,0 +8,0 @@ export default class FlexibleActionsView extends YTNode { |
import { YTNode } from '../helpers.js'; | ||
import { Parser } from '../index.js'; | ||
import ButtonView from './ButtonView.js'; | ||
import ToggleButtonView from './ToggleButtonView.js'; | ||
class FlexibleActionsView extends YTNode { | ||
@@ -8,3 +9,3 @@ constructor(data) { | ||
this.actions_rows = data.actionsRows.map((row) => ({ | ||
actions: Parser.parseArray(row.actions, ButtonView) | ||
actions: Parser.parseArray(row.actions, [ButtonView, ToggleButtonView]) | ||
})); | ||
@@ -11,0 +12,0 @@ this.style = data.style; |
@@ -6,2 +6,3 @@ import { YTNode } from '../helpers.js'; | ||
import Text from './misc/Text.js'; | ||
import NavigationEndpoint from './NavigationEndpoint.js'; | ||
export default class InfoPanelContainer extends YTNode { | ||
@@ -12,5 +13,7 @@ static type: string; | ||
content: InfoPanelContent | null; | ||
header_endpoint?: NavigationEndpoint; | ||
background: string; | ||
title_style?: string; | ||
icon_type?: string; | ||
constructor(data: RawNode); | ||
} |
@@ -6,2 +6,3 @@ import { YTNode } from '../helpers.js'; | ||
import Text from './misc/Text.js'; | ||
import NavigationEndpoint from './NavigationEndpoint.js'; | ||
class InfoPanelContainer extends YTNode { | ||
@@ -14,3 +15,6 @@ constructor(data) { | ||
this.content = Parser.parseItem(data.content, InfoPanelContent); | ||
if (data.headerEndpoint) | ||
this.header_endpoint = new NavigationEndpoint(data.headerEndpoint); | ||
this.background = data.background; | ||
this.title_style = data.titleStyle; | ||
if (Reflect.has(data, 'icon')) { | ||
@@ -17,0 +21,0 @@ this.icon_type = (_a = data.icon) === null || _a === void 0 ? void 0 : _a.iconType; |
@@ -10,3 +10,3 @@ import { YTNode } from '../helpers.js'; | ||
source: Text; | ||
paragraphs: Text[]; | ||
attributed_paragraphs: Text[]; | ||
thumbnail: Thumbnail[]; | ||
@@ -13,0 +13,0 @@ source_endpoint: NavigationEndpoint; |
@@ -10,3 +10,3 @@ import { YTNode } from '../helpers.js'; | ||
this.source = new Text(data.source); | ||
this.paragraphs = data.paragraphs.map((p) => new Text(p)); | ||
this.attributed_paragraphs = data.attributedParagraphs.map((p) => Text.fromAttributed(p)); | ||
this.thumbnail = Thumbnail.fromResponse(data.thumbnail); | ||
@@ -13,0 +13,0 @@ this.source_endpoint = new NavigationEndpoint(data.sourceEndpoint); |
@@ -14,3 +14,3 @@ import { YTNode } from '../helpers.js'; | ||
if (data.targetId || data.sectionIdentifier) { | ||
this.target_id = data.target_id || data.sectionIdentifier; | ||
this.target_id = data.targetId || data.sectionIdentifier; | ||
} | ||
@@ -17,0 +17,0 @@ if (data.continuations) { |
@@ -50,2 +50,3 @@ import type Player from '../../../core/Player.js'; | ||
is_original?: boolean; | ||
is_drc?: boolean; | ||
color_info?: { | ||
@@ -52,0 +53,0 @@ primaries?: string; |
@@ -74,6 +74,7 @@ var _Format_this_response_nsig_cache; | ||
if (this.has_audio) { | ||
this.is_drc = !!data.isDrc || !!(xtags === null || xtags === void 0 ? void 0 : xtags.includes('drc=1')); | ||
const audio_content = (_h = xtags === null || xtags === void 0 ? void 0 : xtags.find((x) => x.startsWith('acont='))) === null || _h === void 0 ? void 0 : _h.split('=')[1]; | ||
this.is_dubbed = audio_content === 'dubbed'; | ||
this.is_descriptive = audio_content === 'descriptive'; | ||
this.is_original = audio_content === 'original' || (!this.is_dubbed && !this.is_descriptive); | ||
this.is_original = audio_content === 'original' || (!this.is_dubbed && !this.is_descriptive && !this.is_drc); | ||
} | ||
@@ -80,0 +81,0 @@ // Some text tracks don't have xtags while others do |
@@ -33,3 +33,3 @@ import type { RawNode } from '../../index.js'; | ||
} | ||
interface AttributedText { | ||
export interface AttributedText { | ||
content: string; | ||
@@ -36,0 +36,0 @@ styleRuns?: StyleRun[]; |
@@ -9,2 +9,3 @@ import { type RawNode } from '../index.js'; | ||
import Menu from './menus/Menu.js'; | ||
import Text from './misc/Text.js'; | ||
import type { ObservedArray } from '../helpers.js'; | ||
@@ -11,0 +12,0 @@ export default class MusicResponsiveHeader extends YTNode { |
@@ -9,2 +9,3 @@ import { Parser } from '../index.js'; | ||
import Menu from './menus/Menu.js'; | ||
import Text from './misc/Text.js'; | ||
class MusicResponsiveHeader extends YTNode { | ||
@@ -11,0 +12,0 @@ constructor(data) { |
@@ -321,3 +321,3 @@ import { __classPrivateFieldGet, __classPrivateFieldSet, __setFunctionName } from "tslib"; | ||
export function createRuntimeClass(classname, key_info, logger) { | ||
var _a, _key_info; | ||
var _a, _node_key_info; | ||
logger({ | ||
@@ -330,6 +330,6 @@ error_type: 'class_not_found', | ||
static set key_info(key_info) { | ||
__classPrivateFieldSet(this, _a, new Map(key_info), "f", _key_info); | ||
__classPrivateFieldSet(this, _a, new Map(key_info), "f", _node_key_info); | ||
} | ||
static get key_info() { | ||
return [...__classPrivateFieldGet(this, _a, "f", _key_info).entries()]; | ||
return [...__classPrivateFieldGet(this, _a, "f", _node_key_info).entries()]; | ||
} | ||
@@ -362,3 +362,3 @@ constructor(data) { | ||
_a.type = classname, | ||
_key_info = { value: new Map() }, | ||
_node_key_info = { value: new Map() }, | ||
_a); | ||
@@ -365,0 +365,0 @@ node.key_info = key_info; |
@@ -49,4 +49,4 @@ import { __awaiter } from "tslib"; | ||
applyFilter(filter) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
let target_filter; | ||
@@ -75,4 +75,4 @@ const filter_chipbar = this.memo.getType(FeedFilterChipBar).first(); | ||
applySort(sort) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
const sort_filter_sub_menu = this.memo.getType(SortFilterSubMenu).first(); | ||
@@ -95,4 +95,4 @@ if (!sort_filter_sub_menu) | ||
applyContentTypeFilter(content_type_filter) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
const sub_menu = (_c = (_b = (_a = this.current_tab) === null || _a === void 0 ? void 0 : _a.content) === null || _b === void 0 ? void 0 : _b.as(SectionList).sub_menu) === null || _c === void 0 ? void 0 : _c.as(ChannelSubMenu); | ||
@@ -177,4 +177,4 @@ if (!sub_menu) | ||
getAbout() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
if (this.hasTabWithURL('about')) { | ||
@@ -208,4 +208,4 @@ const tab = yield this.getTabByURL('about'); | ||
search(query) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
const tab = (_a = this.memo.getType(ExpandableTab)) === null || _a === void 0 ? void 0 : _a[0]; | ||
@@ -212,0 +212,0 @@ if (!tab) |
@@ -38,4 +38,4 @@ var _Comments_page, _Comments_actions, _Comments_continuation; | ||
applySort(sort) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
if (!this.header) | ||
@@ -63,4 +63,4 @@ throw new InnertubeError('Page header is missing. Cannot apply sort option.'); | ||
createComment(text) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!this.header) | ||
@@ -67,0 +67,0 @@ throw new InnertubeError('Page header is missing. Cannot create comment.'); |
@@ -31,4 +31,4 @@ import { __awaiter } from "tslib"; | ||
}); | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const feed = yield _super.getContinuation.call(this); | ||
@@ -35,0 +35,0 @@ // Keep the page header |
@@ -46,4 +46,4 @@ var _Library_instances, _Library_getAll; | ||
_Library_instances = new WeakSet(), _Library_getAll = function _Library_getAll(shelf) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!((_a = shelf.menu) === null || _a === void 0 ? void 0 : _a.as(Menu).hasKey('top_level_buttons'))) | ||
@@ -50,0 +50,0 @@ throw new InnertubeError(`The ${shelf.title.text} shelf doesn't have more items`); |
@@ -32,4 +32,4 @@ import { __awaiter } from "tslib"; | ||
selectRefinementCard(card) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
let target_card; | ||
@@ -36,0 +36,0 @@ if (typeof card === 'string') { |
@@ -18,4 +18,4 @@ var _TranscriptInfo_page, _TranscriptInfo_actions; | ||
selectLanguage(language) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
const target_menu_item = (_d = (_c = (_b = (_a = this.transcript.content) === null || _a === void 0 ? void 0 : _a.footer) === null || _b === void 0 ? void 0 : _b.language_menu) === null || _c === void 0 ? void 0 : _c.sub_menu_items) === null || _d === void 0 ? void 0 : _d.find((item) => item.title.toString() === language); | ||
@@ -22,0 +22,0 @@ if (!target_menu_item) |
@@ -130,4 +130,4 @@ var _VideoInfo_watch_next_continuation; | ||
selectFilter(target_filter) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
if (!this.related_chip_cloud) | ||
@@ -171,4 +171,4 @@ throw new InnertubeError('Chip cloud not found, cannot apply filter'); | ||
getWatchNextContinuation() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
if (!__classPrivateFieldGet(this, _VideoInfo_watch_next_continuation, "f")) | ||
@@ -194,4 +194,4 @@ throw new InnertubeError('Watch next feed continuation not found'); | ||
like() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
const segmented_like_dislike_button_view = (_b = (_a = this.primary_info) === null || _a === void 0 ? void 0 : _a.menu) === null || _b === void 0 ? void 0 : _b.top_level_buttons.firstOfType(SegmentedLikeDislikeButtonView); | ||
@@ -225,4 +225,4 @@ if (segmented_like_dislike_button_view) { | ||
dislike() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
const segmented_like_dislike_button_view = (_b = (_a = this.primary_info) === null || _a === void 0 ? void 0 : _a.menu) === null || _b === void 0 ? void 0 : _b.top_level_buttons.firstOfType(SegmentedLikeDislikeButtonView); | ||
@@ -256,4 +256,4 @@ if (segmented_like_dislike_button_view) { | ||
removeRating() { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
let button; | ||
@@ -260,0 +260,0 @@ const segmented_like_dislike_button_view = (_b = (_a = this.primary_info) === null || _a === void 0 ? void 0 : _a.menu) === null || _b === void 0 ? void 0 : _b.top_level_buttons.firstOfType(SegmentedLikeDislikeButtonView); |
@@ -17,4 +17,4 @@ import { __awaiter } from "tslib"; | ||
getContinuation() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const response = yield this.actions.execute('/browse', { | ||
@@ -21,0 +21,0 @@ continuation: (_a = this.contents) === null || _a === void 0 ? void 0 : _a.continuation, |
@@ -19,4 +19,4 @@ import { __awaiter } from "tslib"; | ||
selectCategoryTab(tab) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
let target_tab; | ||
@@ -23,0 +23,0 @@ if (typeof tab === 'string') { |
@@ -9,6 +9,7 @@ import MusicShelf from '../classes/MusicShelf.js'; | ||
import type { IBrowseResponse } from '../types/ParsedResponse.js'; | ||
import type { ObservedArray } from '../helpers.js'; | ||
declare class Artist { | ||
#private; | ||
header?: MusicImmersiveHeader | MusicVisualHeader | MusicHeader; | ||
sections: (MusicCarouselShelf | MusicShelf)[]; | ||
sections: ObservedArray<MusicCarouselShelf | MusicShelf>; | ||
constructor(response: ApiResponse, actions: Actions); | ||
@@ -15,0 +16,0 @@ getAllSongs(): Promise<MusicPlaylistShelf | undefined>; |
var _Artist_page, _Artist_actions; | ||
import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib"; | ||
import { Parser } from '../index.js'; | ||
import { observe } from '../helpers.js'; | ||
import { InnertubeError } from '../../utils/Utils.js'; | ||
@@ -21,7 +22,7 @@ import MusicShelf from '../classes/MusicShelf.js'; | ||
const music_carousel_shelf = ((_c = __classPrivateFieldGet(this, _Artist_page, "f").contents_memo) === null || _c === void 0 ? void 0 : _c.getType(MusicCarouselShelf)) || []; | ||
this.sections = [...music_shelf, ...music_carousel_shelf]; | ||
this.sections = observe([...music_shelf, ...music_carousel_shelf]); | ||
} | ||
getAllSongs() { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
const music_shelves = this.sections.filter((section) => section.type === 'MusicShelf'); | ||
@@ -28,0 +29,0 @@ if (!music_shelves.length) |
@@ -48,4 +48,4 @@ var _HomeFeed_page, _HomeFeed_actions, _HomeFeed_continuation; | ||
applyFilter(target_filter) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
let cloud_chip; | ||
@@ -52,0 +52,0 @@ if (typeof target_filter === 'string') { |
@@ -31,4 +31,4 @@ var _Library_page, _Library_actions, _Library_continuation, _LibraryContinuation_page, _LibraryContinuation_actions, _LibraryContinuation_continuation; | ||
applySort(sort_by) { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; | ||
let target_item; | ||
@@ -69,4 +69,4 @@ if (typeof sort_by === 'string') { | ||
applyFilter(filter) { | ||
var _a, _b, _c, _d; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
let target_chip; | ||
@@ -73,0 +73,0 @@ const chip_cloud = (_a = __classPrivateFieldGet(this, _Library_page, "f").contents_memo) === null || _a === void 0 ? void 0 : _a.getType(ChipCloud).first(); |
@@ -58,4 +58,4 @@ var _Playlist_instances, _Playlist_page, _Playlist_actions, _Playlist_continuation, _Playlist_last_fetched_suggestions, _Playlist_suggestions_continuation, _Playlist_fetchSuggestions; | ||
getRelated() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
let section_continuation = (_b = (_a = __classPrivateFieldGet(this, _Playlist_page, "f").contents_memo) === null || _a === void 0 ? void 0 : _a.getType(SectionList)) === null || _b === void 0 ? void 0 : _b[0].continuation; | ||
@@ -78,4 +78,4 @@ while (section_continuation) { | ||
} | ||
getSuggestions(refresh = true) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
getSuggestions() { | ||
return __awaiter(this, arguments, void 0, function* (refresh = true) { | ||
const require_fetch = refresh || !__classPrivateFieldGet(this, _Playlist_last_fetched_suggestions, "f"); | ||
@@ -99,4 +99,4 @@ const fetch_promise = require_fetch ? __classPrivateFieldGet(this, _Playlist_instances, "m", _Playlist_fetchSuggestions).call(this) : Promise.resolve(null); | ||
_Playlist_page = new WeakMap(), _Playlist_actions = new WeakMap(), _Playlist_continuation = new WeakMap(), _Playlist_last_fetched_suggestions = new WeakMap(), _Playlist_suggestions_continuation = new WeakMap(), _Playlist_instances = new WeakSet(), _Playlist_fetchSuggestions = function _Playlist_fetchSuggestions() { | ||
var _a, _b, _c, _d, _e; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b, _c, _d, _e; | ||
const continuation = __classPrivateFieldGet(this, _Playlist_suggestions_continuation, "f") || ((_b = (_a = __classPrivateFieldGet(this, _Playlist_page, "f").contents_memo) === null || _a === void 0 ? void 0 : _a.get('SectionList')) === null || _b === void 0 ? void 0 : _b[0].as(SectionList).continuation); | ||
@@ -103,0 +103,0 @@ if (continuation) { |
@@ -69,4 +69,4 @@ var _Search_page, _Search_actions, _Search_continuation, _SearchContinuation_actions, _SearchContinuation_page; | ||
applyFilter(target_filter) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
let cloud_chip; | ||
@@ -161,4 +161,4 @@ if (typeof target_filter === 'string') { | ||
getContinuation() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
if (!((_a = this.contents) === null || _a === void 0 ? void 0 : _a.continuation)) | ||
@@ -165,0 +165,0 @@ throw new InnertubeError('Continuation not found.'); |
@@ -42,4 +42,4 @@ import { __awaiter } from "tslib"; | ||
getTab(title_or_page_type) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
if (!this.tabs) | ||
@@ -65,5 +65,5 @@ throw new InnertubeError('Could not find any tab'); | ||
*/ | ||
getUpNext(automix = true) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
getUpNext() { | ||
return __awaiter(this, arguments, void 0, function* (automix = true) { | ||
var _a, _b; | ||
const music_queue = yield this.getTab('Up next'); | ||
@@ -70,0 +70,0 @@ if (!music_queue || !music_queue.content) |
@@ -22,4 +22,4 @@ var _VideoInfo_watch_next_continuation, _VideoInfo_actions; | ||
getWatchNextContinuation() { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a, _b; | ||
if (!__classPrivateFieldGet(this, _VideoInfo_watch_next_continuation, "f")) | ||
@@ -26,0 +26,0 @@ throw new InnertubeError('Watch next feed continuation not found'); |
@@ -6,3 +6,3 @@ var _Cache_persistent_directory, _Cache_persistent; | ||
import sha1Hash from './polyfills/web-crypto.js'; | ||
const { homepage, version, bugs } = { "homepage": "https://github.com/LuanRT/YouTube.js#readme", "version": "9.4.0", "bugs": { "url": "https://github.com/LuanRT/YouTube.js/issues" } }; | ||
const { homepage, version, bugs } = { "homepage": "https://github.com/LuanRT/YouTube.js#readme", "version": "10.0.0", "bugs": { "url": "https://github.com/LuanRT/YouTube.js/issues" } }; | ||
const repo_url = homepage === null || homepage === void 0 ? void 0 : homepage.split('#')[0]; | ||
@@ -9,0 +9,0 @@ class Cache { |
@@ -5,3 +5,3 @@ import { Jinter } from 'jintr'; | ||
export default function evaluate(code, env) { | ||
Log.info(TAG, 'Evaluating JavaScript.\n', code); | ||
Log.debug(TAG, 'Evaluating JavaScript:\n', code); | ||
const runtime = new Jinter(code); | ||
@@ -12,5 +12,5 @@ for (const [key, value] of Object.entries(env)) { | ||
const result = runtime.interpret(); | ||
Log.info(TAG, 'Done. Result:', result); | ||
Log.debug(TAG, 'Done. Result:', result); | ||
return result; | ||
} | ||
//# sourceMappingURL=jinter.js.map |
@@ -5,3 +5,3 @@ var _Cache_instances, _Cache_persistent_directory, _Cache_persistent, _Cache_createCache; | ||
import { ReadableStream } from 'stream/web'; | ||
import { fetch as defaultFetch, Request, Response, Headers, FormData, File } from 'undici'; | ||
import { fetch as defaultFetch, Request, Response, Headers, FormData, File, setGlobalDispatcher, Agent } from 'undici'; | ||
import { Platform } from '../utils/Utils.js'; | ||
@@ -18,4 +18,9 @@ import crypto from 'crypto'; | ||
const __dirname__ = is_cjs ? __dirname : path.dirname(fileURLToPath(meta_url)); | ||
const { homepage, version, bugs } = { "homepage": "https://github.com/LuanRT/YouTube.js#readme", "version": "9.4.0", "bugs": { "url": "https://github.com/LuanRT/YouTube.js/issues" } }; | ||
const { homepage, version, bugs } = { "homepage": "https://github.com/LuanRT/YouTube.js#readme", "version": "10.0.0", "bugs": { "url": "https://github.com/LuanRT/YouTube.js/issues" } }; | ||
const repo_url = homepage === null || homepage === void 0 ? void 0 : homepage.split('#')[0]; | ||
setGlobalDispatcher(new Agent({ | ||
connect: { | ||
timeout: 60000 | ||
} | ||
})); | ||
class Cache { | ||
@@ -22,0 +27,0 @@ constructor(persistent = false, persistent_directory) { |
@@ -44,3 +44,3 @@ export type Method<TMetadata = any, THeader = any, TTrailer = any, TServiceName extends string = string, TMethodName extends string = string, TRequestStream extends boolean = boolean, TResponseStream extends boolean = boolean, TReq = any, TRes = any> = [ | ||
export declare function createServerImplBuilder<TMetadata, THeader, TTrailer>(): { | ||
register<TReq, TRes>(methodDescriptor: MethodDescriptor<TReq, TRes, string, string, boolean, boolean>, handler: MethodImplHandler<TReq, TRes, TMetadata, THeader, TTrailer>): void; | ||
register<TReq, TRes>(methodDescriptor: MethodDescriptor<TReq, TRes>, handler: MethodImplHandler<TReq, TRes, TMetadata, THeader, TTrailer>): void; | ||
finish: () => void; | ||
@@ -47,0 +47,0 @@ drain: () => AsyncGenerator<Method<TMetadata, THeader, TTrailer, string, string, boolean, boolean, any, any>, any, unknown>; |
@@ -1,2 +0,3 @@ | ||
export interface DashOptions { | ||
import type { StreamingInfoOptions } from './StreamingInfoOptions.js'; | ||
export interface DashOptions extends StreamingInfoOptions { | ||
/** | ||
@@ -3,0 +4,0 @@ * Include the storyboards in the DASH manifest when YouTube provides them. |
import type { ICacheConstructor } from './Cache.js'; | ||
export type Runtime = 'deno' | 'node' | 'browser' | 'cf-worker' | 'unknown'; | ||
export type Runtime = 'deno' | 'node' | 'browser' | 'cf-worker' | 'unknown' | 'react-native'; | ||
export type FetchFunction = typeof fetch; | ||
@@ -4,0 +4,0 @@ export type VMPrimative = string | number | boolean | null | undefined; |
@@ -18,15 +18,4 @@ export declare const URLS: Readonly<{ | ||
export declare const OAUTH: Readonly<{ | ||
SCOPE: "http://gdata.youtube.com https://www.googleapis.com/auth/youtube-paid-content"; | ||
GRANT_TYPE: "http://oauth.net/grant_type/device/1.0"; | ||
MODEL_NAME: "ytlr::"; | ||
HEADERS: Readonly<{ | ||
accept: "*/*"; | ||
origin: "https://www.youtube.com"; | ||
'user-agent': "Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version"; | ||
'content-type': "application/json"; | ||
referer: "https://www.youtube.com/tv"; | ||
'accept-language': "en-US"; | ||
}>; | ||
REGEX: Readonly<{ | ||
AUTH_SCRIPT: RegExp; | ||
TV_SCRIPT: RegExp; | ||
CLIENT_IDENTITY: RegExp; | ||
@@ -33,0 +22,0 @@ }>; |
@@ -18,16 +18,5 @@ export const URLS = Object.freeze({ | ||
export const OAUTH = Object.freeze({ | ||
SCOPE: 'http://gdata.youtube.com https://www.googleapis.com/auth/youtube-paid-content', | ||
GRANT_TYPE: 'http://oauth.net/grant_type/device/1.0', | ||
MODEL_NAME: 'ytlr::', | ||
HEADERS: Object.freeze({ | ||
'accept': '*/*', | ||
'origin': 'https://www.youtube.com', | ||
'user-agent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version', | ||
'content-type': 'application/json', | ||
'referer': 'https://www.youtube.com/tv', | ||
'accept-language': 'en-US' | ||
}), | ||
REGEX: Object.freeze({ | ||
AUTH_SCRIPT: /<script id="base-js" src="(.*?)" nonce=".*?"><\/script>/, | ||
CLIENT_IDENTITY: /var .+?={clientId:"(?<client_id>.+?)",.+?:"(?<client_secret>.+?)".+?}/ | ||
TV_SCRIPT: new RegExp('<script\\s+id="base-js"\\s+src="([^"]+)"[^>]*><\\/script>'), | ||
CLIENT_IDENTITY: new RegExp('clientId:"(?<client_id>[^"]+)",[^"]*?:"(?<client_secret>[^"]+)"') | ||
}) | ||
@@ -34,0 +23,0 @@ }); |
@@ -7,2 +7,3 @@ import type Actions from '../core/Actions.js'; | ||
import type PlayerLiveStoryboardSpec from '../parser/classes/PlayerLiveStoryboardSpec.js'; | ||
export declare function toDash(streaming_data?: IStreamingData, is_post_live_dvr?: boolean, url_transformer?: URLTransformer, format_filter?: FormatFilter, cpn?: string, player?: Player, actions?: Actions, storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec): Promise<string>; | ||
import type { StreamingInfoOptions } from '../types/StreamingInfoOptions.js'; | ||
export declare function toDash(streaming_data?: IStreamingData, is_post_live_dvr?: boolean, url_transformer?: URLTransformer, format_filter?: FormatFilter, cpn?: string, player?: Player, actions?: Actions, storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec, options?: StreamingInfoOptions): Promise<string>; |
@@ -8,4 +8,4 @@ import { __awaiter } from "tslib"; | ||
import { InnertubeError } from './Utils.js'; | ||
function OTFPostLiveDvrSegmentInfo({ info }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
function OTFPostLiveDvrSegmentInfo(_a) { | ||
return __awaiter(this, arguments, void 0, function* ({ info }) { | ||
if (!info.is_oft && !info.is_post_live_dvr) | ||
@@ -27,5 +27,5 @@ return null; | ||
} | ||
function DashManifest({ streamingData, isPostLiveDvr, transformURL, rejectFormat, cpn, player, actions, storyboards }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { getDuration, audio_sets, video_sets, image_sets } = getStreamingInfo(streamingData, isPostLiveDvr, transformURL, rejectFormat, cpn, player, actions, storyboards); | ||
function DashManifest(_a) { | ||
return __awaiter(this, arguments, void 0, function* ({ streamingData, isPostLiveDvr, transformURL, rejectFormat, cpn, player, actions, storyboards, options }) { | ||
const { getDuration, audio_sets, video_sets, image_sets } = getStreamingInfo(streamingData, isPostLiveDvr, transformURL, rejectFormat, cpn, player, actions, storyboards, options); | ||
// XXX: DASH spec: https://standards.iso.org/ittf/PubliclyAvailableStandards/c083314_ISO_IEC%2023009-1_2022(en).zip | ||
@@ -35,4 +35,3 @@ return DashUtils.createElement("mpd", { xmlns: "urn:mpeg:dash:schema:mpd:2011", minBufferTime: "PT1.500S", profiles: "urn:mpeg:dash:profile:isoff-main:2011", type: "static", mediaPresentationDuration: `PT${yield getDuration()}S`, "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation": "urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd" }, | ||
audio_sets.map((set, index) => (DashUtils.createElement("adaptation-set", { id: index, mimeType: set.mime_type, startWithSAP: "1", subsegmentAlignment: "true", lang: set.language, codecs: set.codecs, audioSamplingRate: set.audio_sample_rate, contentType: "audio" }, | ||
set.track_role && | ||
DashUtils.createElement("role", { schemeIdUri: "urn:mpeg:dash:role:2011", value: set.track_role }), | ||
set.track_roles && set.track_roles.map((role) => (DashUtils.createElement("role", { schemeIdUri: "urn:mpeg:dash:role:2011", value: role }))), | ||
set.track_name && | ||
@@ -64,7 +63,7 @@ DashUtils.createElement("label", { id: index }, set.track_name), | ||
} | ||
export function toDash(streaming_data, is_post_live_dvr = false, url_transformer = (url) => url, format_filter, cpn, player, actions, storyboards) { | ||
export function toDash(streaming_data, is_post_live_dvr = false, url_transformer = (url) => url, format_filter, cpn, player, actions, storyboards, options) { | ||
if (!streaming_data) | ||
throw new InnertubeError('Streaming data not available'); | ||
return DashUtils.renderToString(DashUtils.createElement(DashManifest, { streamingData: streaming_data, isPostLiveDvr: is_post_live_dvr, transformURL: url_transformer, rejectFormat: format_filter, cpn: cpn, player: player, actions: actions, storyboards: storyboards })); | ||
return DashUtils.renderToString(DashUtils.createElement(DashManifest, { streamingData: streaming_data, isPostLiveDvr: is_post_live_dvr, transformURL: url_transformer, options: options, rejectFormat: format_filter, cpn: cpn, player: player, actions: actions, storyboards: storyboards })); | ||
} | ||
//# sourceMappingURL=DashManifest.js.map |
@@ -92,3 +92,3 @@ import { __asyncValues, __awaiter } from "tslib"; | ||
}, { | ||
highWaterMark: 1, | ||
highWaterMark: 1, // TODO: better value? | ||
size(chunk) { | ||
@@ -95,0 +95,0 @@ return chunk.byteLength; |
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'; | ||
import { Platform, generateSidAuth, getRandomUserAgent, InnertubeError, getCookie } from './Utils.js'; | ||
class HTTPClient { | ||
@@ -45,3 +45,3 @@ constructor(session, cookie, fetch) { | ||
request_headers.set('User-Agent', getRandomUserAgent('desktop')); | ||
request_headers.set('origin', request_url.origin); | ||
request_headers.set('Origin', request_url.origin); | ||
} | ||
@@ -62,3 +62,3 @@ request_url.searchParams.set('prettyPrint', 'false'); | ||
__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); | ||
request_headers.set('X-Youtube-Client-Version', n_body.context.client.clientVersion); | ||
const client_constant = Object.values(Constants.CLIENTS).find((client) => { | ||
@@ -71,11 +71,9 @@ return client.NAME === n_body.context.client.clientName; | ||
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); | ||
request_headers.set('X-GOOG-API-FORMAT-VERSION', '2'); | ||
} | ||
else if (n_body.context.client.clientName === 'iOS') { | ||
request_headers.set('User-Agent', Constants.CLIENTS.iOS.USER_AGENT); | ||
} | ||
if (n_body.context.client.clientName === 'ANDROID' || n_body.context.client.clientName === 'ANDROID_MUSIC') { | ||
request_headers.set('User-Agent', Constants.CLIENTS.ANDROID.USER_AGENT); | ||
request_headers.set('X-GOOG-API-FORMAT-VERSION', '2'); | ||
} | ||
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'; | ||
@@ -95,13 +93,15 @@ request_body = JSON.stringify(n_body); | ||
const oauth = __classPrivateFieldGet(this, _HTTPClient_session, "f").oauth; | ||
if (oauth.validateCredentials()) { | ||
yield oauth.refreshIfRequired(); | ||
request_headers.set('authorization', `Bearer ${oauth.credentials.access_token}`); | ||
if (oauth.oauth2_tokens) { | ||
if (oauth.shouldRefreshToken()) { | ||
yield oauth.refreshAccessToken(); | ||
} | ||
request_headers.set('Authorization', `Bearer ${oauth.oauth2_tokens.access_token}`); | ||
} | ||
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()); | ||
const sapisid = getCookie(__classPrivateFieldGet(this, _HTTPClient_cookie, "f"), 'SAPISID'); | ||
if (sapisid) { | ||
request_headers.set('Authorization', yield generateSidAuth(sapisid)); | ||
request_headers.set('X-Goog-Authuser', __classPrivateFieldGet(this, _HTTPClient_session, "f").account_index.toString()); | ||
} | ||
request_headers.set('cookie', __classPrivateFieldGet(this, _HTTPClient_cookie, "f")); | ||
request_headers.set('Cookie', __classPrivateFieldGet(this, _HTTPClient_cookie, "f")); | ||
} | ||
@@ -108,0 +108,0 @@ } |
@@ -10,1 +10,2 @@ export { default as UniversalCache } from './Cache.js'; | ||
export { default as Log } from './Log.js'; | ||
export * as LZW from './LZW.js'; |
@@ -10,2 +10,3 @@ export { default as UniversalCache } from './Cache.js'; | ||
export { default as Log } from './Log.js'; | ||
export * as LZW from './LZW.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -25,8 +25,8 @@ var _a; | ||
Log.log_map_ = { | ||
[Log.Level.ERROR]: (...args) => console.error(...args), | ||
[Log.Level.WARNING]: (...args) => console.warn(...args), | ||
[Log.Level.INFO]: (...args) => console.info(...args), | ||
[Log.Level.DEBUG]: (...args) => console.debug(...args) | ||
[_a.Level.ERROR]: (...args) => console.error(...args), | ||
[_a.Level.WARNING]: (...args) => console.warn(...args), | ||
[_a.Level.INFO]: (...args) => console.info(...args), | ||
[_a.Level.DEBUG]: (...args) => console.debug(...args) | ||
}; | ||
Log.log_level_ = [Log.Level.WARNING]; | ||
Log.log_level_ = [_a.Level.WARNING]; | ||
Log.one_time_warnings_issued_ = new Set(); | ||
@@ -36,10 +36,10 @@ Log.warnOnce = (id, ...args) => { | ||
return; | ||
_a.doLog(Log.Level.WARNING, id, args); | ||
_a.doLog(_a.Level.WARNING, id, args); | ||
_a.one_time_warnings_issued_.add(id); | ||
}; | ||
Log.warn = (tag, ...args) => _a.doLog(Log.Level.WARNING, tag, args); | ||
Log.error = (tag, ...args) => _a.doLog(Log.Level.ERROR, tag, args); | ||
Log.info = (tag, ...args) => _a.doLog(Log.Level.INFO, tag, args); | ||
Log.debug = (tag, ...args) => _a.doLog(Log.Level.DEBUG, tag, args); | ||
Log.warn = (tag, ...args) => _a.doLog(_a.Level.WARNING, tag, args); | ||
Log.error = (tag, ...args) => _a.doLog(_a.Level.ERROR, tag, args); | ||
Log.info = (tag, ...args) => _a.doLog(_a.Level.INFO, tag, args); | ||
Log.debug = (tag, ...args) => _a.doLog(_a.Level.DEBUG, tag, args); | ||
export default Log; | ||
//# sourceMappingURL=Log.js.map |
@@ -7,2 +7,3 @@ import PlayerStoryboardSpec from '../parser/classes/PlayerStoryboardSpec.js'; | ||
import type { FormatFilter, URLTransformer } from '../types/FormatUtils.js'; | ||
import type { StreamingInfoOptions } from '../types/StreamingInfoOptions.js'; | ||
export interface StreamingInfo { | ||
@@ -20,3 +21,3 @@ getDuration(): Promise<number>; | ||
track_name?: string; | ||
track_role?: 'main' | 'dub' | 'description' | 'alternate'; | ||
track_roles?: ('main' | 'dub' | 'description' | 'enhanced-audio-intelligibility' | 'alternate')[]; | ||
channels?: number; | ||
@@ -104,2 +105,2 @@ representations: AudioRepresentation[]; | ||
} | ||
export declare function getStreamingInfo(streaming_data?: IStreamingData, is_post_live_dvr?: boolean, url_transformer?: URLTransformer, format_filter?: FormatFilter, cpn?: string, player?: Player, actions?: Actions, storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec): StreamingInfo; | ||
export declare function getStreamingInfo(streaming_data?: IStreamingData, is_post_live_dvr?: boolean, url_transformer?: URLTransformer, format_filter?: FormatFilter, cpn?: string, player?: Player, actions?: Actions, storyboards?: PlayerStoryboardSpec | PlayerLiveStoryboardSpec, options?: StreamingInfoOptions): StreamingInfo; |
@@ -21,3 +21,4 @@ import { __awaiter } from "tslib"; | ||
const audio_track_id = ((_b = format.audio_track) === null || _b === void 0 ? void 0 : _b.id) || ''; | ||
const group_id = `${mime_type}-${just_codec}-${color_info}-${audio_track_id}`; | ||
const drc = format.is_drc ? 'drc' : ''; | ||
const group_id = `${mime_type}-${just_codec}-${color_info}-${audio_track_id}-${drc}`; | ||
if (!group_info.has(group_id)) { | ||
@@ -53,4 +54,4 @@ group_info.set(group_id, []); | ||
function getOTFSegmentTemplate(url, actions) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
// Fetch the first segment as it contains the segment durations which we need to generate the manifest | ||
@@ -188,4 +189,11 @@ const response = yield actions.session.http.fetch_function(`${url}&rn=0&sq=0`, { | ||
url.searchParams.set('cpn', cpn || ''); | ||
const uid_parts = [format.itag.toString()]; | ||
if (format.audio_track) { | ||
uid_parts.push(format.audio_track.id); | ||
} | ||
if (format.is_drc) { | ||
uid_parts.push('drc'); | ||
} | ||
const rep = { | ||
uid: format.audio_track ? `${format.itag}-${format.audio_track.id}` : format.itag.toString(), | ||
uid: uid_parts.join('-'), | ||
bitrate: format.bitrate, | ||
@@ -199,15 +207,18 @@ codecs: !hoisted.includes('codecs') ? getStringBetweenStrings(format.mime_type, 'codecs="', '"') : undefined, | ||
} | ||
function getTrackRole(format) { | ||
const { audio_track } = format; | ||
if (!audio_track) | ||
function getTrackRoles(format, has_drc_streams) { | ||
if (!format.audio_track && !has_drc_streams) { | ||
return; | ||
if (audio_track.audio_is_default) | ||
return 'main'; | ||
} | ||
const roles = [ | ||
format.is_original ? 'main' : 'alternate' | ||
]; | ||
if (format.is_dubbed) | ||
return 'dub'; | ||
roles.push('dub'); | ||
if (format.is_descriptive) | ||
return 'description'; | ||
return 'alternate'; | ||
roles.push('description'); | ||
if (format.is_drc) | ||
roles.push('enhanced-audio-intelligibility'); | ||
return roles; | ||
} | ||
function getAudioSet(formats, url_transformer, actions, player, cpn, shared_post_live_dvr_info) { | ||
function getAudioSet(formats, url_transformer, actions, player, cpn, shared_post_live_dvr_info, drc_labels) { | ||
var _a; | ||
@@ -217,2 +228,15 @@ const first_format = formats[0]; | ||
const hoisted = []; | ||
const has_drc_streams = !!drc_labels; | ||
let track_name; | ||
if (audio_track) { | ||
if (has_drc_streams && first_format.is_drc) { | ||
track_name = drc_labels.label_drc_mutiple(audio_track.display_name); | ||
} | ||
else { | ||
track_name = audio_track.display_name; | ||
} | ||
} | ||
else if (has_drc_streams) { | ||
track_name = first_format.is_drc ? drc_labels.label_drc : drc_labels.label_original; | ||
} | ||
const set = { | ||
@@ -223,4 +247,4 @@ mime_type: first_format.mime_type.split(';')[0], | ||
audio_sample_rate: hoistNumberAttributeIfPossible(formats, 'audio_sample_rate', hoisted), | ||
track_name: audio_track === null || audio_track === void 0 ? void 0 : audio_track.display_name, | ||
track_role: getTrackRole(first_format), | ||
track_name, | ||
track_roles: getTrackRoles(first_format, has_drc_streams), | ||
channels: hoistAudioChannelsIfPossible(formats, hoisted), | ||
@@ -413,3 +437,3 @@ representations: formats.map((format) => getAudioRepresentation(format, hoisted, url_transformer, actions, player, cpn, shared_post_live_dvr_info)) | ||
} | ||
export function getStreamingInfo(streaming_data, is_post_live_dvr = false, url_transformer = (url) => url, format_filter, cpn, player, actions, storyboards) { | ||
export function getStreamingInfo(streaming_data, is_post_live_dvr = false, url_transformer = (url) => url, format_filter, cpn, player, actions, storyboards, options) { | ||
if (!streaming_data) | ||
@@ -457,3 +481,11 @@ throw new InnertubeError('Streaming data not available'); | ||
}); | ||
const audio_sets = audio_groups.map((formats) => getAudioSet(formats, url_transformer, actions, player, cpn, shared_post_live_dvr_info)); | ||
let drc_labels; | ||
if (audio_groups.flat().some((format) => format.is_drc)) { | ||
drc_labels = { | ||
label_original: (options === null || options === void 0 ? void 0 : options.label_original) || 'Original', | ||
label_drc: (options === null || options === void 0 ? void 0 : options.label_drc) || 'Stable Volume', | ||
label_drc_mutiple: (options === null || options === void 0 ? void 0 : options.label_drc_mutiple) || ((display_name) => `${display_name} (Stable Volume)`) | ||
}; | ||
} | ||
const audio_sets = audio_groups.map((formats) => getAudioSet(formats, url_transformer, actions, player, cpn, shared_post_live_dvr_info, drc_labels)); | ||
const video_sets = video_groups.map((formats) => getVideoSet(formats, url_transformer, player, actions, cpn, shared_post_live_dvr_info)); | ||
@@ -460,0 +492,0 @@ let image_sets = []; |
@@ -20,3 +20,3 @@ import { Memo } from '../parser/helpers.js'; | ||
} | ||
export declare class OAuthError extends InnertubeError { | ||
export declare class OAuth2Error extends InnertubeError { | ||
} | ||
@@ -71,1 +71,2 @@ export declare class PlayerError extends Error { | ||
export declare function isTextRun(run: TextRun | EmojiRun): run is TextRun; | ||
export declare function getCookie(cookies: string, name: string, matchWholeName?: boolean): string | undefined; |
@@ -10,9 +10,9 @@ var _a, _Platform_shim; | ||
static load(platform) { | ||
__classPrivateFieldSet(Platform, _a, platform, "f", _Platform_shim); | ||
__classPrivateFieldSet(_a, _a, platform, "f", _Platform_shim); | ||
} | ||
static get shim() { | ||
if (!__classPrivateFieldGet(Platform, _a, "f", _Platform_shim)) { | ||
if (!__classPrivateFieldGet(_a, _a, "f", _Platform_shim)) { | ||
throw new Error('Platform is not loaded'); | ||
} | ||
return __classPrivateFieldGet(Platform, _a, "f", _Platform_shim); | ||
return __classPrivateFieldGet(_a, _a, "f", _Platform_shim); | ||
} | ||
@@ -36,3 +36,3 @@ } | ||
} | ||
export class OAuthError extends InnertubeError { | ||
export class OAuth2Error extends InnertubeError { | ||
} | ||
@@ -208,2 +208,7 @@ export class PlayerError extends Error { | ||
} | ||
export function getCookie(cookies, name, matchWholeName = false) { | ||
const regex = matchWholeName ? `(^|\\s?)\\b${name}\\b=([^;]+)` : `(^|s?)${name}=([^;]+)`; | ||
const match = cookies.match(new RegExp(regex)); | ||
return match ? match[2] : undefined; | ||
} | ||
//# sourceMappingURL=Utils.js.map |
{ | ||
"name": "youtubei.js", | ||
"version": "9.4.0", | ||
"version": "10.0.0", | ||
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).", | ||
@@ -15,2 +15,5 @@ "type": "module", | ||
], | ||
"react-native": [ | ||
"./dist/src/platform/lib.d.ts" | ||
], | ||
"web.bundle": [ | ||
@@ -36,2 +39,3 @@ "./dist/src/platform/lib.d.ts" | ||
"browser": "./dist/src/platform/web.js", | ||
"react-native": "./dist/src/platform/react-native.js", | ||
"default": "./dist/src/platform/web.js" | ||
@@ -47,2 +51,6 @@ }, | ||
}, | ||
"./react-native": { | ||
"types": "./dist/src/platform/lib.d.ts", | ||
"default": "./dist/src/platform/react-native.js" | ||
}, | ||
"./web.bundle": { | ||
@@ -81,4 +89,5 @@ "types": "./dist/src/platform/lib.d.ts", | ||
"lint:fix": "npx eslint --fix ./src", | ||
"build": "npm run build:parser-map && npm run build:proto && npm run build:esm && npm run bundle:node && npm run bundle:browser && npm run bundle:browser:prod && npm run bundle:cf-worker", | ||
"build:parser-map": "node ./scripts/gen-parser-map.mjs", | ||
"clean": "npx rimraf ./dist/src ./dist/package.json ./bundle/browser.js ./bundle/browser.js.map ./bundle/browser.min.js ./bundle/browser.min.js.map ./bundle/node.cjs ./bundle/node.cjs.map ./bundle/cf-worker.js ./bundle/cf-worker.js.map ./bundle/react-native.js ./bundle/react-native.js.map ./deno", | ||
"build": "npm run clean && npm run build:parser-map && npm run build:proto && npm run build:esm && npm run bundle:node && npm run bundle:browser && npm run bundle:browser:prod && npm run bundle:cf-worker && npm run bundle:react-native", | ||
"build:parser-map": "node ./dev-scripts/gen-parser-map.mjs", | ||
"build:proto": "npx pb-gen-ts --entry-path=\"src/proto\" --out-dir=\"src/proto/generated\" --ext-in-import=\".js\"", | ||
@@ -89,2 +98,3 @@ "build:esm": "npx tspc", | ||
"bundle:browser": "npx esbuild ./dist/src/platform/web.js --banner:js=\"/* eslint-disable */\" --bundle --target=chrome58 --keep-names --format=esm --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/browser.js --platform=browser", | ||
"bundle:react-native": "npx esbuild ./dist/src/platform/react-native.js --bundle --target=es2020 --keep-names --format=esm --platform=neutral --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/react-native.js", | ||
"bundle:browser:prod": "npm run bundle:browser -- --outfile=./bundle/browser.min.js --minify", | ||
@@ -119,6 +129,6 @@ "bundle:cf-worker": "npx esbuild ./dist/src/platform/cf-worker.js --banner:js=\"/* eslint-disable */\" --bundle --target=es2020 --keep-names --format=esm --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/cf-worker.js --platform=node", | ||
"glob": "^8.0.3", | ||
"jest": "^28.1.3", | ||
"jest": "^29.7.0", | ||
"pbkit": "^0.0.59", | ||
"replace": "^1.2.2", | ||
"ts-jest": "^28.0.8", | ||
"ts-jest": "^29.1.4", | ||
"ts-patch": "^3.0.2", | ||
@@ -125,0 +135,0 @@ "ts-transformer-inline-file": "^0.2.0", |
@@ -13,49 +13,30 @@ <!-- BADGE LINKS --> | ||
<h1 align=center>YouTube.js</h1> | ||
<p align=center>A full-featured wrapper around the InnerTube API</p> | ||
<div align="center"> | ||
<br/> | ||
<p> | ||
<a href="https://github.com/LuanRT/YouTube.js"><img src="https://luanrt.github.io/assets/img/ytjs.svg" title="youtube.js" alt="YouTube.js' Github Page" width="200" /></a> | ||
</p> | ||
<p align="center">A full-featured wrapper around the InnerTube API</p> | ||
[![Discord](https://img.shields.io/badge/discord-online-brightgreen.svg)][discord] | ||
[![CI](https://github.com/LuanRT/YouTube.js/actions/workflows/test.yml/badge.svg)][actions] | ||
[![NPM Version](https://img.shields.io/npm/v/youtubei.js?color=%2335C757)][versions] | ||
[![Downloads](https://img.shields.io/npm/dt/youtubei.js)][npm] | ||
[![Codefactor](https://www.codefactor.io/repository/github/luanrt/youtube.js/badge)][codefactor] | ||
[![Downloads](https://img.shields.io/npm/dt/youtubei.js)][npm] | ||
[![Discord](https://img.shields.io/badge/discord-online-brightgreen.svg)][discord] | ||
<h5> | ||
Sponsored by <a href="https://serpapi.com"><img src="https://luanrt.github.io/assets/img/serpapi.svg" alt="SerpApi - API to get search engine results with ease." height=35 valign="middle"></a> | ||
</h5> | ||
<br> | ||
[![Donate](https://img.shields.io/badge/donate-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#white)][collaborators] | ||
</div> | ||
<div align="center"> | ||
<p> | ||
<sup>Special thanks to:</sup> | ||
<br> | ||
<br> | ||
<a href="https://serpapi.com" target="_blank"> | ||
<img width="80" alt="SerpApi" src="https://luanrt.github.io/assets/img/serpapi.svg" /> | ||
<br> | ||
<sub> | ||
API to get search engine results with ease. | ||
</sub> | ||
</a> | ||
</p> | ||
</div> | ||
<br> | ||
<hr> | ||
<br> | ||
InnerTube is an API used by all YouTube clients. It was created to simplify the deployment of new features and experiments across the platform [^1]. This library manages all low-level communication with InnerTube, providing a simple and efficient way to interact with YouTube programmatically. Its design aims to closely emulate an actual client, including the parsing of API responses. | ||
## Table of Contents | ||
If you have any questions or need help, feel free to reach out to us on our [Discord server][discord] or open an issue [here](https://github.com/LuanRT/YouTube.js/issues). | ||
### Table of Contents | ||
<ol> | ||
<li><a href="#prerequisites">Prerequisites</a></li> | ||
<li><a href="#installation">Installation</a></li> | ||
<li> | ||
<a href="#description">Description</a> | ||
</li> | ||
<li> | ||
<a href="#getting-started">Getting Started</a> | ||
<ul> | ||
<li><a href="#prerequisites">Prerequisites</a></li> | ||
<li><a href="#installation">Installation</a></li> | ||
</ul> | ||
</li> | ||
<li> | ||
<a href="#usage">Usage</a> | ||
@@ -66,5 +47,5 @@ <ul> | ||
<li><a href="#api">API</a></li> | ||
<li><a href="#extending-the-library">Extending the library</a></li> | ||
</ul> | ||
</li> | ||
<li><a href="#extending-the-library">Extending the library</a></li> | ||
<li><a href="#contributing">Contributing</a></li> | ||
@@ -76,10 +57,2 @@ <li><a href="#contact">Contact</a></li> | ||
## Description | ||
InnerTube is an API used by all YouTube clients. It was created to simplify the deployment of new features and experiments across the platform [^1]. This library manages all low-level communication with InnerTube, providing a simple and efficient way to interact with YouTube programmatically. Its design aims to closely emulate an actual client, including the parsing of API responses. | ||
If you have any questions or need help, feel free to reach out to us on our [Discord server][discord] or open an issue [here](https://github.com/LuanRT/YouTube.js/issues). | ||
## Getting Started | ||
### Prerequisites | ||
@@ -91,3 +64,3 @@ YouTube.js runs on Node.js, Deno, and modern browsers. | ||
- On Node, we use [undici](https://github.com/nodejs/undici)'s fetch implementation, which requires Node.js 16.8+. If you need to use an older version, you may provide your own fetch implementation. See [providing your own fetch implementation](#custom-fetch) for more information. | ||
- The `Response` object returned by fetch must thus be spec compliant and return a `ReadableStream` object if you want to use the `VideoInfo#download` method. (Implementations like `node-fetch` returns a non-standard `Readable` object.) | ||
- The `Response` object returned by fetch must thus be spec compliant and return a `ReadableStream` object if you want to use the `VideoInfo#download` method. (Implementations like `node-fetch` return a non-standard `Readable` object.) | ||
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) and [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) are required. | ||
@@ -121,3 +94,3 @@ | ||
### Initialization Options | ||
### Options | ||
<details> | ||
@@ -134,7 +107,8 @@ <summary>Click to expand</summary> | ||
| `enable_safety_mode` | `boolean` | Specifies whether to enable safety mode. This will prevent the session from loading any potentially unsafe content. | `false` | | ||
| `generate_session_locally` | `boolean` | Specifies whether to generate the session data locally or retrieve it from YouTube. This can be useful if you need more performance. | `false` | | ||
| `generate_session_locally` | `boolean` | Specifies whether to generate the session data locally or retrieve it from YouTube. This can be useful if you need more performance. **NOTE:** If you are using the cache option and a session has already been generated, this will be ignored. If you want to force a new session to be generated, you must clear the cache or disable session caching. | `false` | | ||
| `enable_session_cache` | `boolean` | Specifies whether to cache the session data. | `true` | | ||
| `device_category` | `DeviceCategory` | Platform to use for the session. | `DESKTOP` | | ||
| `client_type` | `ClientType` | InnerTube client type. | `WEB` | | ||
| `timezone` | `string` | The time zone. | `*` | | ||
| `cache` | `ICache` | Used to cache the deciphering functions from the JS player. | `undefined` | | ||
| `cache` | `ICache` | Used to cache algorithms, session data, and OAuth2 tokens. | `undefined` | | ||
| `cookie` | `string` | YouTube cookies. | `undefined` | | ||
@@ -145,3 +119,3 @@ | `fetch` | `FetchFunction` | Fetch function to use. | `fetch` | | ||
## Browser Usage | ||
### Browser Usage | ||
To use YouTube.js in the browser, you must proxy requests through your own server. You can see our simple reference implementation in Deno at [`examples/browser/proxy/deno.ts`](https://github.com/LuanRT/YouTube.js/tree/main/examples/browser/proxy/deno.ts). | ||
@@ -205,3 +179,3 @@ | ||
## Providing your own fetch implementation | ||
### Providing your own fetch implementation | ||
You may provide your own fetch implementation to be used by YouTube.js. This can be useful in some cases to modify the requests before they are sent and transform the responses before they are returned (eg. for proxies). | ||
@@ -223,3 +197,3 @@ ```ts | ||
## Caching | ||
### Caching | ||
Caching the transformed player instance can greatly improve the performance. Our `UniversalCache` implementation uses different caching methods depending on the environment. | ||
@@ -249,3 +223,3 @@ | ||
## API | ||
### API | ||
@@ -710,3 +684,3 @@ * `Innertube` | ||
## Extending the library | ||
### Extending the library | ||
@@ -819,4 +793,4 @@ YouTube.js is modular and easy to extend. Most of the methods, classes, and utilities used internally are exposed and can be used to implement your own extensions without having to modify the library's source code. | ||
<p align=" right"> | ||
<p align="right"> | ||
(<a href="#top">back to top</a>) | ||
</p> | ||
</p> |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11154228
2041
131620
784