@@ -9,10 +9,12 @@ 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
13
- * @returns {Promise<string> }
14
+ * @param {string } context
15
+ * @returns {Promise<{ contentPoToken: string, sessionPoToken: string }> }
14
16
*/
15
- export async function generatePoToken ( visitorData ) {
17
+ export async function generatePoToken ( videoId , visitorData , context ) {
16
18
const sessionUuid = crypto . randomUUID ( )
17
19
18
20
const theSession = session . fromPartition ( `potoken-${ sessionUuid } ` , { cache : false } )
@@ -21,12 +23,28 @@ export async function generatePoToken(visitorData) {
21
23
// eslint-disable-next-line n/no-callback-literal
22
24
theSession . setPermissionRequestHandler ( ( webContents , permission , callback ) => callback ( false ) )
23
25
24
- theSession . setUserAgent (
25
- theSession . getUserAgent ( )
26
- . split ( ' ' )
27
- . filter ( part => ! part . includes ( 'Electron' ) )
28
- . join ( ' ' )
29
- )
26
+ theSession . setUserAgent ( session . defaultSession . getUserAgent ( ) )
27
+
28
+ theSession . webRequest . onBeforeSendHeaders ( {
29
+ urls : [ 'https://www.google.com/js/*' , 'https://www.youtube.com/youtubei/*' ]
30
+ } , ( { requestHeaders, url } , callback ) => {
31
+ if ( url . startsWith ( 'https://www.youtube.com/youtubei/' ) ) {
32
+ // make InnerTube requests work with the fetch function
33
+ // InnerTube rejects requests if the referer isn't YouTube or empty
34
+ requestHeaders . Referer = 'https://www.youtube.com/'
35
+ requestHeaders . Origin = 'https://www.youtube.com'
36
+
37
+ requestHeaders [ 'Sec-Fetch-Site' ] = 'same-origin'
38
+ requestHeaders [ 'Sec-Fetch-Mode' ] = 'same-origin'
39
+ requestHeaders [ 'X-Youtube-Bootstrap-Logged-In' ] = 'false'
40
+ } else {
41
+ requestHeaders [ 'Sec-Fetch-Dest' ] = 'script'
42
+ requestHeaders [ 'Sec-Fetch-Site' ] = 'cross-site'
43
+ requestHeaders [ 'Accept-Language' ] = '*'
44
+ }
45
+
46
+ callback ( { requestHeaders } )
47
+ } )
30
48
31
49
const webContentsView = new WebContentsView ( {
32
50
webPreferences : {
@@ -35,7 +53,8 @@ export async function generatePoToken(visitorData) {
35
53
sandbox : true ,
36
54
v8CacheOptions : 'none' ,
37
55
session : theSession ,
38
- offscreen : true
56
+ offscreen : true ,
57
+ webSecurity : false
39
58
}
40
59
} )
41
60
@@ -51,43 +70,8 @@ export async function generatePoToken(visitorData) {
51
70
52
71
webContentsView . webContents . debugger . attach ( )
53
72
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
- }
73
+ await webContentsView . webContents . loadURL ( 'data:text/html,<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>' , {
74
+ baseURLForDataURL : 'https://www.youtube.com/'
91
75
} )
92
76
93
77
await webContentsView . webContents . debugger . sendCommand ( 'Emulation.setDeviceMetricsOverride' , {
@@ -105,7 +89,7 @@ export async function generatePoToken(visitorData) {
105
89
}
106
90
} )
107
91
108
- const script = await getScript ( visitorData )
92
+ const script = await getScript ( videoId , visitorData , context )
109
93
110
94
const response = await webContentsView . webContents . executeJavaScript ( script )
111
95
@@ -118,9 +102,11 @@ export async function generatePoToken(visitorData) {
118
102
let cachedScript
119
103
120
104
/**
105
+ * @param {string } videoId
121
106
* @param {string } visitorData
107
+ * @param {string } context
122
108
*/
123
- async function getScript ( visitorData ) {
109
+ async function getScript ( videoId , visitorData , context ) {
124
110
if ( ! cachedScript ) {
125
111
const pathToScript = process . env . NODE_ENV === 'development'
126
112
? join ( __dirname , '../../dist/botGuardScript.js' )
@@ -133,8 +119,8 @@ async function getScript(visitorData) {
133
119
134
120
const functionName = match [ 1 ]
135
121
136
- cachedScript = content . replace ( match [ 0 ] , `;${ functionName } ("FT_VISITOR_DATA" )` )
122
+ cachedScript = content . replace ( match [ 0 ] , `;${ functionName } (FT_PARAMS )` )
137
123
}
138
124
139
- return cachedScript . replace ( 'FT_VISITOR_DATA ' , visitorData )
125
+ return cachedScript . replace ( 'FT_PARAMS ' , `" ${ videoId } "," ${ visitorData } ", ${ context } ` )
140
126
}
0 commit comments