@@ -9,11 +9,13 @@ import { join } from 'path'
9
9
* This is intentionally split out into it's own thing, with it's own temporary in-memory session,
10
10
* as the BotGuard stuff accesses the global `document` and `window` objects and also requires making some requests.
11
11
* 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
12
13
* @param {string } visitorData
14
+ * @param {string } context
13
15
* @param {string|undefined } proxyUrl
14
- * @returns {Promise<string> }
16
+ * @returns {Promise<{ contentPoToken: string, sessionPoToken: string } > }
15
17
*/
16
- export async function generatePoToken ( visitorData , proxyUrl ) {
18
+ export async function generatePoToken ( videoId , visitorData , context , proxyUrl ) {
17
19
const sessionUuid = crypto . randomUUID ( )
18
20
19
21
const theSession = session . fromPartition ( `potoken-${ sessionUuid } ` , { cache : false } )
@@ -22,27 +24,44 @@ export async function generatePoToken(visitorData, proxyUrl) {
22
24
// eslint-disable-next-line n/no-callback-literal
23
25
theSession . setPermissionRequestHandler ( ( webContents , permission , callback ) => callback ( false ) )
24
26
25
- theSession . setUserAgent (
26
- theSession . getUserAgent ( )
27
- . split ( ' ' )
28
- . filter ( part => ! part . includes ( 'Electron' ) )
29
- . join ( ' ' )
30
- )
27
+ theSession . setUserAgent ( session . defaultSession . getUserAgent ( ) )
31
28
32
29
if ( proxyUrl ) {
33
30
await theSession . setProxy ( {
34
31
proxyRules : proxyUrl
35
32
} )
36
33
}
37
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
+ } )
55
+
38
56
const webContentsView = new WebContentsView ( {
39
57
webPreferences : {
40
58
backgroundThrottling : false ,
41
59
safeDialogs : true ,
42
60
sandbox : true ,
43
61
v8CacheOptions : 'none' ,
44
62
session : theSession ,
45
- offscreen : true
63
+ offscreen : true ,
64
+ webSecurity : false
46
65
}
47
66
} )
48
67
@@ -58,43 +77,8 @@ export async function generatePoToken(visitorData, proxyUrl) {
58
77
59
78
webContentsView . webContents . debugger . attach ( )
60
79
61
- await webContentsView . webContents . loadURL ( 'data:text/html,' , {
62
- baseURLForDataURL : 'https://www.youtube.com'
63
- } )
64
-
65
- await webContentsView . webContents . debugger . sendCommand ( 'Emulation.setUserAgentOverride' , {
66
- userAgent : theSession . getUserAgent ( ) ,
67
- acceptLanguage : 'en-US' ,
68
- platform : 'Win32' ,
69
- userAgentMetadata : {
70
- brands : [
71
- {
72
- brand : 'Not/A)Brand' ,
73
- version : '99'
74
- } ,
75
- {
76
- brand : 'Chromium' ,
77
- version : process . versions . chrome . split ( '.' ) [ 0 ]
78
- }
79
- ] ,
80
- fullVersionList : [
81
- {
82
- brand : 'Not/A)Brand' ,
83
- version : '99.0.0.0'
84
- } ,
85
- {
86
- brand : 'Chromium' ,
87
- version : process . versions . chrome
88
- }
89
- ] ,
90
- platform : 'Windows' ,
91
- platformVersion : '10.0.0' ,
92
- architecture : 'x86' ,
93
- model : '' ,
94
- mobile : false ,
95
- bitness : '64' ,
96
- wow64 : false
97
- }
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/'
98
82
} )
99
83
100
84
await webContentsView . webContents . debugger . sendCommand ( 'Emulation.setDeviceMetricsOverride' , {
@@ -112,7 +96,7 @@ export async function generatePoToken(visitorData, proxyUrl) {
112
96
}
113
97
} )
114
98
115
- const script = await getScript ( visitorData )
99
+ const script = await getScript ( videoId , visitorData , context )
116
100
117
101
const response = await webContentsView . webContents . executeJavaScript ( script )
118
102
@@ -125,9 +109,11 @@ export async function generatePoToken(visitorData, proxyUrl) {
125
109
let cachedScript
126
110
127
111
/**
112
+ * @param {string } videoId
128
113
* @param {string } visitorData
114
+ * @param {string } context
129
115
*/
130
- async function getScript ( visitorData ) {
116
+ async function getScript ( videoId , visitorData , context ) {
131
117
if ( ! cachedScript ) {
132
118
const pathToScript = process . env . NODE_ENV === 'development'
133
119
? join ( __dirname , '../../dist/botGuardScript.js' )
@@ -140,8 +126,8 @@ async function getScript(visitorData) {
140
126
141
127
const functionName = match [ 1 ]
142
128
143
- cachedScript = content . replace ( match [ 0 ] , `;${ functionName } ("FT_VISITOR_DATA" )` )
129
+ cachedScript = content . replace ( match [ 0 ] , `;${ functionName } (FT_PARAMS )` )
144
130
}
145
131
146
- return cachedScript . replace ( 'FT_VISITOR_DATA ' , visitorData )
132
+ return cachedScript . replace ( 'FT_PARAMS ' , `" ${ videoId } "," ${ visitorData } ", ${ context } ` )
147
133
}
0 commit comments