chore: Fix onesie request example and clean up

This commit is contained in:
Luan
2025-04-06 19:12:24 -03:00
parent d72f8b2dae
commit 159237ff92
27 changed files with 1721 additions and 389 deletions

View File

@@ -1,5 +1,4 @@
import Innertube, { Constants, UniversalCache } from 'youtubei.js';
import { type Context, YT } from 'youtubei.js';
import Innertube, { Constants, type Context, UniversalCache, YT } from 'youtubei.js';
import GoogleVideo, { base64ToU8, PART, Protos, QUALITY } from '../../dist/src/index.js';
import { decryptResponse, encryptRequest } from './utils.js';
@@ -67,7 +66,7 @@ async function prepareOnesieRequest(args: OnesieRequestArgs): Promise<OnesieRequ
// Change or remove these if you want to use a different client. I chose TVHTML5 purely for testing.
clonedInnerTubeContext.client.clientName = Constants.CLIENTS.TV.NAME;
clonedInnerTubeContext.client.clientVersion = Constants.CLIENTS.TV.VERSION;
const params: Record<string, any> = {
playbackContext: {
contentPlaybackContext: {
@@ -79,29 +78,31 @@ async function prepareOnesieRequest(args: OnesieRequestArgs): Promise<OnesieRequ
},
videoId
};
if (poToken) {
params.serviceIntegrityDimensions = {};
params.serviceIntegrityDimensions.poToken = poToken;
}
const playerRequestJson = {
context: clonedInnerTubeContext,
...params
};
const headers = [ {
name: 'Content-Type',
value: 'application/json'
},
{
name: 'User-Agent',
value: innertube.session.context.client.userAgent
},
{
name: 'X-Goog-Visitor-Id',
value: innertube.session.context.client.visitorData
} ];
const headers = [
{
name: 'Content-Type',
value: 'application/json'
},
{
name: 'User-Agent',
value: innertube.session.context.client.userAgent
},
{
name: 'X-Goog-Visitor-Id',
value: innertube.session.context.client.visitorData
}
];
const onesieRequest = Protos.OnesiePlayerRequest.encode({
url: 'https://youtubei.googleapis.com/youtubei/v1/player?key=AIzaSyDCU8hByM-4DrUqRUYnGn-3llEO78bcxq8',
@@ -122,15 +123,13 @@ async function prepareOnesieRequest(args: OnesieRequestArgs): Promise<OnesieRequ
* If you want to use an unencrypted player request:
* unencryptedOnesiePlayerRequest: onesieRequest,
*/
enableCompression: false,
enableCompression: true,
hmac: hmac,
iv: iv,
TQ: true,
useJsonformatterToParsePlayerResponse: false,
serializeResponseAsJson: true // If false, the response will be serialized as protobuf.
},
clientAbrState: {
timeSinceLastManualFormatSelectionMs: 0,
lastManualDirection: 0,
lastManualSelectedResolution: QUALITY.HD720,
stickyResolution: QUALITY.HD720,
playerTimeMs: 0,
@@ -142,7 +141,7 @@ async function prepareOnesieRequest(args: OnesieRequestArgs): Promise<OnesieRequ
poToken: poToken ? base64ToU8(poToken) : undefined,
playbackCookie: undefined,
clientInfo: {
clientName: parseInt(Constants.CLIENTS.TV.NAME_ID),
clientName: parseInt(Constants.CLIENT_NAME_IDS[clonedInnerTubeContext.client.clientName as keyof typeof Constants.CLIENT_NAME_IDS]),
clientVersion: clonedInnerTubeContext.client.clientVersion
}
},
@@ -190,7 +189,7 @@ async function getBasicInfo(innertube: Innertube, videoId: string): Promise<YT.V
method: 'POST',
headers: {
'accept': '*/*',
'content-type': 'text/plain'
'content-type': 'application/octet-stream'
},
referrer: 'https://www.youtube.com/',
body: onesieRequest.body
@@ -218,7 +217,7 @@ async function getBasicInfo(innertube: Innertube, videoId: string): Promise<YT.V
}
});
const onesiePlayerResponse = onesie.find((header) => header.type === Protos.OnesieHeaderType.PLAYER_RESPONSE);
const onesiePlayerResponse = onesie.find((header) => header.type === Protos.OnesieHeaderType.ONESIE_PLAYER_RESPONSE);
if (onesiePlayerResponse) {
if (!onesiePlayerResponse.cryptoParams)
@@ -227,8 +226,23 @@ async function getBasicInfo(innertube: Innertube, videoId: string): Promise<YT.V
const iv = onesiePlayerResponse.cryptoParams.iv;
const hmac = onesiePlayerResponse.cryptoParams.hmac;
let responseData = onesiePlayerResponse.data;
// Decompress the response data if compression is enabled.
if (responseData && onesiePlayerResponse.cryptoParams.compressionType === Protos.CompressionType.GZIP) {
if (typeof window === 'undefined') {
const zlib = await import('node:zlib');
responseData = new Uint8Array(zlib.gunzipSync(responseData));
} else {
const ds = new DecompressionStream('gzip');
const stream = new Blob([ responseData ]).stream().pipeThrough(ds);
responseData = await new Response(stream).arrayBuffer().then((buf) => new Uint8Array(buf));
}
}
// If skipResponseEncryption is set to true in the request, the response will not be encrypted.
const decryptedData = hmac?.length && iv?.length ? await decryptResponse(iv, hmac, onesiePlayerResponse.data, clientConfig.clientKeyData) : onesiePlayerResponse.data!;
const decryptedData = hmac?.length && iv?.length ?
await decryptResponse(iv, hmac, responseData, clientConfig.clientKeyData) : responseData!;
const response = Protos.OnesiePlayerResponse.decode(decryptedData);
if (response.onesieProxyStatus !== Protos.OnesieProxyStatus.ONESIE_PROXY_STATUS_OK)
@@ -253,4 +267,9 @@ const innertube = await Innertube.create({ cache: new UniversalCache(true) });
const videoInfo = await getBasicInfo(innertube, 'JAs6WyK-Kr0');
console.log('Basic info:', videoInfo);
console.log('Deciphered audio URL:', videoInfo.chooseFormat({ format: 'mp4', quality: 'best', type: 'audio' }).decipher(innertube.session.player));
console.log('Deciphered audio URL:');
console.log(videoInfo.chooseFormat({
format: 'mp4',
quality: 'best',
type: 'audio'
}).decipher(innertube.session.player));

View File

@@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"youtubei.js": "^12.2.0"
"youtubei.js": "^13.3.0"
}
},
"node_modules/@bufbuild/protobuf": {
@@ -26,9 +26,9 @@
}
},
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -38,9 +38,9 @@
}
},
"node_modules/jintr": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jintr/-/jintr-3.2.0.tgz",
"integrity": "sha512-psD1yf05kMKDNsUdW1l5YhO59pHScQ6OIHHb8W5SKSM2dCOFPsqolmIuSHgVA8+3Dc47NJR181CXZ4alCAPTkA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/jintr/-/jintr-3.3.0.tgz",
"integrity": "sha512-ZsaajJ4Hr5XR0tSPhOZOTjFhxA0qscKNSOs41NRjx7ZOGwpfdp8NKIBEUtvUPbA37JXyv1sJlgeOOZHjr3h76Q==",
"funding": [
"https://github.com/sponsors/LuanRT"
],
@@ -66,16 +66,16 @@
}
},
"node_modules/youtubei.js": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-12.2.0.tgz",
"integrity": "sha512-G+50qrbJCToMYhu8jbaHiS3Vf+RRul+CcDbz3hEGwHkGPh+zLiWwD6SS+YhYF+2/op4ZU5zDYQJrGqJ+wKh7Gw==",
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-13.3.0.tgz",
"integrity": "sha512-tbl7rxltpgKoSsmfGUe9JqWUAzv6HFLqrOn0N85EbTn5DLt24EXrjClnXdxyr3PBARMJ3LC4vbll100a0ABsYw==",
"funding": [
"https://github.com/sponsors/LuanRT"
],
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.0.0",
"jintr": "^3.2.0",
"jintr": "^3.3.0",
"tslib": "^2.5.0",
"undici": "^5.19.1"
}

View File

@@ -12,6 +12,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"youtubei.js": "^12.2.0"
"youtubei.js": "^13.3.0"
}
}