@@ -9,10 +9,13 @@ import { join } from 'path'
99 * This is intentionally split out into it's own thing, with it's own temporary in-memory session,
1010 * as the BotGuard stuff accesses the global `document` and `window` objects and also requires making some requests.
1111 * So we definitely don't want it running in the same places as the rest of the FreeTube code with the user data.
12+ * @param {string } videoId
1213 * @param {string } visitorData
13- * @returns {Promise<string> }
14+ * @param {string } context
15+ * @param {string|undefined } proxyUrl
16+ * @returns {Promise<{ contentPoToken: string, sessionPoToken: string }> }
1417 */
15- export async function generatePoToken ( visitorData ) {
18+ export async function generatePoToken ( videoId , visitorData , context , proxyUrl ) {
1619 const sessionUuid = crypto . randomUUID ( )
1720
1821 const theSession = session . fromPartition ( `potoken-${ sessionUuid } ` , { cache : false } )
@@ -21,12 +24,34 @@ export async function generatePoToken(visitorData) {
2124 // eslint-disable-next-line n/no-callback-literal
2225 theSession . setPermissionRequestHandler ( ( webContents , permission , callback ) => callback ( false ) )
2326
24- theSession . setUserAgent (
25- theSession . getUserAgent ( )
26- . split ( ' ' )
27- . filter ( part => ! part . includes ( 'Electron' ) )
28- . join ( ' ' )
29- )
27+ theSession . setUserAgent ( session . defaultSession . getUserAgent ( ) )
28+
29+ if ( proxyUrl ) {
30+ await theSession . setProxy ( {
31+ proxyRules : proxyUrl
32+ } )
33+ }
34+
35+ theSession . webRequest . onBeforeSendHeaders ( {
36+ urls : [ 'https://www.google.com/js/*' , 'https://www.youtube.com/youtubei/*' ]
37+ } , ( { requestHeaders, url } , callback ) => {
38+ if ( url . startsWith ( 'https://www.youtube.com/youtubei/' ) ) {
39+ // make InnerTube requests work with the fetch function
40+ // InnerTube rejects requests if the referer isn't YouTube or empty
41+ requestHeaders . Referer = 'https://www.youtube.com/'
42+ requestHeaders . Origin = 'https://www.youtube.com'
43+
44+ requestHeaders [ 'Sec-Fetch-Site' ] = 'same-origin'
45+ requestHeaders [ 'Sec-Fetch-Mode' ] = 'same-origin'
46+ requestHeaders [ 'X-Youtube-Bootstrap-Logged-In' ] = 'false'
47+ } else {
48+ requestHeaders [ 'Sec-Fetch-Dest' ] = 'script'
49+ requestHeaders [ 'Sec-Fetch-Site' ] = 'cross-site'
50+ requestHeaders [ 'Accept-Language' ] = '*'
51+ }
52+
53+ callback ( { requestHeaders } )
54+ } )
3055
3156 const webContentsView = new WebContentsView ( {
3257 webPreferences : {
@@ -35,7 +60,8 @@ export async function generatePoToken(visitorData) {
3560 sandbox : true ,
3661 v8CacheOptions : 'none' ,
3762 session : theSession ,
38- offscreen : true
63+ offscreen : true ,
64+ webSecurity : false
3965 }
4066 } )
4167
@@ -51,43 +77,8 @@ export async function generatePoToken(visitorData) {
5177
5278 webContentsView . webContents . debugger . attach ( )
5379
54- await webContentsView . webContents . loadURL ( 'data:text/html,' , {
55- baseURLForDataURL : 'https://www.youtube.com'
56- } )
57-
58- await webContentsView . webContents . debugger . sendCommand ( 'Emulation.setUserAgentOverride' , {
59- userAgent : theSession . getUserAgent ( ) ,
60- acceptLanguage : 'en-US' ,
61- platform : 'Win32' ,
62- userAgentMetadata : {
63- brands : [
64- {
65- brand : 'Not/A)Brand' ,
66- version : '99'
67- } ,
68- {
69- brand : 'Chromium' ,
70- version : process . versions . chrome . split ( '.' ) [ 0 ]
71- }
72- ] ,
73- fullVersionList : [
74- {
75- brand : 'Not/A)Brand' ,
76- version : '99.0.0.0'
77- } ,
78- {
79- brand : 'Chromium' ,
80- version : process . versions . chrome
81- }
82- ] ,
83- platform : 'Windows' ,
84- platformVersion : '10.0.0' ,
85- architecture : 'x86' ,
86- model : '' ,
87- mobile : false ,
88- bitness : '64' ,
89- wow64 : false
90- }
80+ await webContentsView . webContents . loadURL ( 'data:text/html,<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>' , {
81+ baseURLForDataURL : 'https://www.youtube.com/'
9182 } )
9283
9384 await webContentsView . webContents . debugger . sendCommand ( 'Emulation.setDeviceMetricsOverride' , {
@@ -105,7 +96,7 @@ export async function generatePoToken(visitorData) {
10596 }
10697 } )
10798
108- const script = await getScript ( visitorData )
99+ const script = await getScript ( videoId , visitorData , context )
109100
110101 const response = await webContentsView . webContents . executeJavaScript ( script )
111102
@@ -118,9 +109,11 @@ export async function generatePoToken(visitorData) {
118109let cachedScript
119110
120111/**
112+ * @param {string } videoId
121113 * @param {string } visitorData
114+ * @param {string } context
122115 */
123- async function getScript ( visitorData ) {
116+ async function getScript ( videoId , visitorData , context ) {
124117 if ( ! cachedScript ) {
125118 const pathToScript = process . env . NODE_ENV === 'development'
126119 ? join ( __dirname , '../../dist/botGuardScript.js' )
@@ -133,8 +126,8 @@ async function getScript(visitorData) {
133126
134127 const functionName = match [ 1 ]
135128
136- cachedScript = content . replace ( match [ 0 ] , `;${ functionName } ("FT_VISITOR_DATA" )` )
129+ cachedScript = content . replace ( match [ 0 ] , `;${ functionName } (FT_PARAMS )` )
137130 }
138131
139- return cachedScript . replace ( 'FT_VISITOR_DATA ' , visitorData )
132+ return cachedScript . replace ( 'FT_PARAMS ' , `" ${ videoId } "," ${ visitorData } ", ${ context } ` )
140133}
0 commit comments