@@ -44,17 +44,42 @@ async function fetchYouTubeCaptions(videoId: string): Promise<{
4444 const INNERTUBE_CLIENT_VERSION = "20.10.38" ;
4545
4646 try {
47+ // Acquire fresh visitorData token to bypass LOGIN_REQUIRED in Cloudflare datacenters
48+ let visitorData : string | undefined ;
49+ try {
50+ const pageResp = await fetch ( `https://www.youtube.com/watch?v=${ videoId } ` , {
51+ headers : {
52+ "User-Agent" :
53+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" ,
54+ "Accept-Language" : "en-US,en;q=0.9" ,
55+ } ,
56+ } ) ;
57+ if ( pageResp . ok ) {
58+ const html = await pageResp . text ( ) ;
59+ const match = html . match ( / " v i s i t o r D a t a " : " ( [ ^ " ] + ) " / ) ;
60+ if ( match ) {
61+ visitorData = match [ 1 ] ;
62+ }
63+ }
64+ } catch { }
65+
66+ const requestHeaders : Record < string , string > = {
67+ "Content-Type" : "application/json" ,
68+ "User-Agent" : `com.google.android.youtube/${ INNERTUBE_CLIENT_VERSION } (Linux; U; Android 14)` ,
69+ } ;
70+ if ( visitorData ) {
71+ requestHeaders [ "X-Goog-Visitor-Id" ] = visitorData ;
72+ }
73+
4774 const response = await fetch ( INNERTUBE_API_URL , {
4875 method : "POST" ,
49- headers : {
50- "Content-Type" : "application/json" ,
51- "User-Agent" : `com.google.android.youtube/${ INNERTUBE_CLIENT_VERSION } (Linux; U; Android 14)` ,
52- } ,
76+ headers : requestHeaders ,
5377 body : JSON . stringify ( {
5478 context : {
5579 client : {
5680 clientName : "ANDROID" ,
5781 clientVersion : INNERTUBE_CLIENT_VERSION ,
82+ ...( visitorData ? { visitorData } : { } ) ,
5883 } ,
5984 } ,
6085 videoId,
0 commit comments