youtube.js (2779B)
1 import axios from 'axios'; 2 import vm from 'vm'; 3 4 let videoId = 'aqz-KE-bpKQ'; 5 6 /** 7 * From the Youtube API, retrieve metadata about the video (title, video format and audio format) 8 */ 9 async function retrieveMetadata(videoId) { 10 const response = await axios.post('https://www.youtube.com/youtubei/v1/player', { 11 "videoId": videoId, 12 "context": { 13 "client": { "clientName": "WEB", "clientVersion": "2.20230810.05.00" } 14 } 15 }); 16 17 const formats = response.data.streamingData.adaptiveFormats; 18 19 return [ 20 response.data.videoDetails.title, 21 formats.filter(w => w.mimeType.startsWith("video/webm"))[0], 22 formats.filter(w => w.mimeType.startsWith("audio/webm"))[0], 23 ]; 24 } 25 26 /** 27 * From the Youtube Web Page, retrieve the challenge algorithm for the n query parameter 28 */ 29 async function retrieveChallenge(video_id){ 30 31 /** 32 * Find the URL of the javascript file for the current player version 33 */ 34 async function retrieve_player_url(video_id) { 35 let response = await axios.get('https://www.youtube.com/embed/' + video_id); 36 let player_hash = /\/s\/player\/(\w+)\/player_ias.vflset\/\w+\/base.js/.exec(response.data)[1] 37 return `https://www.youtube.com/s/player/${player_hash}/player_ias.vflset/en_US/base.js` 38 } 39 40 const player_url = await retrieve_player_url(video_id); 41 42 const response = await axios.get(player_url); 43 let challenge_name = /\.get\("n"\)\)&&\(b=([a-zA-Z0-9$]+)(?:\[(\d+)\])?\([a-zA-Z0-9]\)/.exec(response.data)[1]; 44 challenge_name = new RegExp(`var ${challenge_name}\\s*=\\s*\\[(.+?)\\]\\s*[,;]`).exec(response.data)[1]; 45 46 const challenge = new RegExp(`${challenge_name}\\s*=\\s*function\\s*\\(([\\w$]+)\\)\\s*{(.+?}\\s*return\\ [\\w$]+.join\\(""\\))};`, "s").exec(response.data)[2]; 47 48 return challenge; 49 } 50 51 /** 52 * Solve the challenge and replace the n query parameter from the url 53 */ 54 function solveChallenge(challenge, formatUrl) { 55 const url = new URL(formatUrl); 56 57 const n = url.searchParams.get("n"); 58 const n_transformed = vm.runInNewContext(`((a) => {${challenge}})('${n}')`); 59 60 url.searchParams.set("n", n_transformed); 61 return url.toString(); 62 } 63 64 65 console.log() 66 console.log("Retrieving metadata") 67 const [title, video, audio] = await retrieveMetadata(videoId); 68 const challenge = await retrieveChallenge(videoId); 69 70 console.log() 71 console.log("Solving challenge") 72 video.url = solveChallenge(challenge, video.url); 73 audio.url = solveChallenge(challenge, audio.url); 74 75 export async function get_url(video_id){ 76 const [title, video, audio] = await retrieveMetadata(video_id); 77 audio.url = solveChallenge(challenge, audio.url); 78 return(audio.url); 79 }