11import { Constants } from "youtubei.js" ;
22import { youtubeFetch } from "./youtube-fetch.ts" ;
3+ import { parseYoutubePageAttestation } from "./youtube-page-attestation.ts" ;
34
45export const WEB_CLIENT_VERSION = Constants . CLIENTS . WEB . VERSION ;
5- const ATT_GET_URL = "https://www.youtube.com/youtubei/v1/att/get?prettyPrint=false" ;
6- const WAA_API_KEY = "AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw" ;
7- const USER_AGENT =
6+ export const WEB_USER_AGENT =
87 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " +
98 "Chrome/131.0.0.0 Safari/537.3" ;
9+ const YOUTUBE_HOME_URL = "https://www.youtube.com/" ;
1010
1111type AttGetChallenge = {
1212 interpreterJavascript ?: {
@@ -23,6 +23,7 @@ export type BotGuardChallenge = {
2323 interpreterScript : string ;
2424 program : string ;
2525 globalName : string ;
26+ eventId : string ;
2627} ;
2728
2829async function resolveInterpreterScript ( challenge : AttGetChallenge ) : Promise < string > {
@@ -51,46 +52,29 @@ async function resolveInterpreterScript(challenge: AttGetChallenge): Promise<str
5152}
5253
5354export async function fetchChallenge ( visitorData : string ) : Promise < BotGuardChallenge > {
54- const response = await youtubeFetch ( ATT_GET_URL , {
55- method : "POST" ,
55+ const response = await youtubeFetch ( YOUTUBE_HOME_URL , {
5656 headers : {
57- "Content-Type " : "application/json" ,
58- "User-Agent" : USER_AGENT ,
59- Accept : "application/json " ,
57+ "User-Agent " : WEB_USER_AGENT ,
58+ Accept : "text/html,application/xhtml+xml" ,
59+ " Accept-Language" : "en-US,en;q=0.7 " ,
6060 "X-Goog-Visitor-Id" : visitorData ,
61- "X-Youtube-Client-Name" : "1" ,
62- "X-Youtube-Client-Version" : WEB_CLIENT_VERSION ,
63- "x-goog-api-key" : WAA_API_KEY ,
64- "x-user-agent" : "grpc-web-javascript/0.1" ,
6561 } ,
66- body : JSON . stringify ( {
67- engagementType : "ENGAGEMENT_TYPE_UNBOUND" ,
68- context : {
69- client : {
70- clientName : "WEB" ,
71- clientVersion : WEB_CLIENT_VERSION ,
72- hl : "en" ,
73- gl : "US" ,
74- utcOffsetMinutes : 0 ,
75- visitorData,
76- } ,
77- } ,
78- } ) ,
7962 } ) ;
8063
8164 if ( ! response . ok ) {
82- throw new Error ( `att/get request failed: ${ response . status } ` ) ;
65+ throw new Error ( `YouTube page request failed: ${ response . status } ` ) ;
8366 }
8467
85- const data = ( await response . json ( ) ) as { bgChallenge ?: AttGetChallenge } ;
68+ const page = parseYoutubePageAttestation ( await response . text ( ) ) ;
69+ const data = JSON . parse ( page . rawChallenge ) as { bgChallenge ?: AttGetChallenge } ;
8670 const challenge = data . bgChallenge ;
8771
8872 if (
8973 ! challenge ||
9074 typeof challenge . program !== "string" ||
9175 typeof challenge . globalName !== "string"
9276 ) {
93- throw new Error ( "att/get response missing a usable BotGuard challenge" ) ;
77+ throw new Error ( "YouTube page has no usable BotGuard challenge" ) ;
9478 }
9579
9680 const interpreterScript = await resolveInterpreterScript ( challenge ) ;
@@ -99,5 +83,6 @@ export async function fetchChallenge(visitorData: string): Promise<BotGuardChall
9983 interpreterScript,
10084 program : challenge . program ,
10185 globalName : challenge . globalName ,
86+ eventId : page . eventId ,
10287 } ;
10388}
0 commit comments