-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinnertube-challenge-fetcher-example.ts
109 lines (87 loc) · 3.77 KB
/
innertube-challenge-fetcher-example.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import type { WebPoSignalOutput } from '../../dist/index.js';
import { BG, buildURL, GOOG_API_KEY, USER_AGENT } from '../../dist/index.js';
import { Innertube, YT, YTNodes } from 'youtubei.js';
import { JSDOM } from 'jsdom';
const userAgent = USER_AGENT;
// @NOTE: Session cache is disabled so we can get a fresh visitor data string.
const innertube = await Innertube.create({ user_agent: userAgent, enable_session_cache: false });
const visitorData = innertube.session.context.client.visitorData || '';
// #region BotGuard Initialization
const dom = new JSDOM('<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>', {
url: 'https://www.youtube.com/',
referrer: 'https://www.youtube.com/',
userAgent
});
Object.assign(globalThis, {
window: dom.window,
document: dom.window.document,
location: dom.window.location,
origin: dom.window.origin
});
if (!Reflect.has(globalThis, 'navigator')) {
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator });
}
const challengeResponse = await innertube.getAttestationChallenge('ENGAGEMENT_TYPE_UNBOUND');
if (!challengeResponse.bg_challenge)
throw new Error('Could not get challenge');
const interpreterUrl = challengeResponse.bg_challenge.interpreter_url.private_do_not_access_or_else_trusted_resource_url_wrapped_value;
const bgScriptResponse = await fetch(`https:${interpreterUrl}`);
const interpreterJavascript = await bgScriptResponse.text();
if (interpreterJavascript) {
new Function(interpreterJavascript)();
} else throw new Error('Could not load VM');
const botguard = await BG.BotGuardClient.create({
program: challengeResponse.bg_challenge.program,
globalName: challengeResponse.bg_challenge.global_name,
globalObj: globalThis
});
// #endregion
// #region WebPO Token Generation
const webPoSignalOutput: WebPoSignalOutput = [];
const botguardResponse = await botguard.snapshot({ webPoSignalOutput });
const requestKey = 'O43z0dpjhgX20SCx4KAo';
const integrityTokenResponse = await fetch(buildURL('GenerateIT', true), {
method: 'POST',
headers: {
'content-type': 'application/json+protobuf',
'x-goog-api-key': GOOG_API_KEY,
'x-user-agent': 'grpc-web-javascript/0.1',
'user-agent': userAgent
},
body: JSON.stringify([ requestKey, botguardResponse ])
});
const response = await integrityTokenResponse.json() as unknown[];
if (typeof response[0] !== 'string')
throw new Error('Could not get integrity token');
const integrityTokenBasedMinter = await BG.WebPoMinter.create({ integrityToken: response[0] }, webPoSignalOutput);
// #endregion
// #region YouTube.js Usage Example
const videoId = 'EBFDLgqn8pw';
const contentPoToken = await integrityTokenBasedMinter.mintAsWebsafeString(videoId);
const sessionPoToken = await integrityTokenBasedMinter.mintAsWebsafeString(visitorData);
const watchEndpoint = new YTNodes.NavigationEndpoint({ watchEndpoint: { videoId } });
const extraRequestArgs = {
playbackContext: {
contentPlaybackContext: {
vis: 0,
splay: false,
lactMilliseconds: '-1',
signatureTimestamp: innertube.session.player?.sts
}
},
serviceIntegrityDimensions: {
poToken: contentPoToken
}
};
const watchResponse = await watchEndpoint.call(innertube.actions, extraRequestArgs);
const videoInfo = new YT.VideoInfo([ watchResponse ], innertube.actions, '');
const audioStreamingURL = `${videoInfo.chooseFormat({
quality: 'best',
type: 'audio'
}).decipher(innertube.session.player)}&pot=${sessionPoToken}`;
console.info('Visitor data:', decodeURIComponent(visitorData));
console.info('Content WebPO Token:', contentPoToken);
console.info('Session WebPO Token:', sessionPoToken);
console.info('Cold Start WebPO Token:', BG.PoToken.generateColdStartToken(visitorData), '\n');
console.info('Streaming URL:', audioStreamingURL);
// #endregion