node-ytdl-core icon indicating copy to clipboard operation
node-ytdl-core copied to clipboard

MinigetError: Status code: 403

Open Namnp1521 opened this issue 1 year ago • 14 comments

I run on the local successfully but I got this error when run on the firebase function cloud.

image

version: "axios": "^1.2.0", "ytdl-core": "^4.11.5"

Namnp1521 avatar May 23 '24 14:05 Namnp1521

I have faces the same problem , I got this error when run on the server.

shubham-ralli avatar May 23 '24 16:05 shubham-ralli

Is there any update

shubham-ralli avatar May 28 '24 12:05 shubham-ralli

on dev it works fine, but on prod it breaks, Is there any solution ?

mdanish1326 avatar Jun 13 '24 10:06 mdanish1326

I ended up looking at yt-dlp to figure out why they do not get 403'd. I also needed to use fetch (which is built-in, now, and needed in places like cloudflare workers) instead of a http-lib. This javascript code works, without any deps:

export async function getInfo (videoId) {
  // hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py
  const apiKey = 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc'

  const headers = {
    'X-YouTube-Client-Name': '5',
    'X-YouTube-Client-Version': '19.09.3',
    Origin: 'https://www.youtube.com',
    'User-Agent': 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
    'content-type': 'application/json'
  }

  const b = {
    context: {
      client: {
        clientName: 'IOS',
        clientVersion: '19.09.3',
        deviceModel: 'iPhone14,3',
        userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
        hl: 'en',
        timeZone: 'UTC',
        utcOffsetMinutes: 0
      }
    },
    videoId,
    playbackContext: { contentPlaybackContext: { html5Preference: 'HTML5_PREF_WANTS' } },
    contentCheckOk: true,
    racyCheckOk: true
  }

  return fetch(`https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false`, { method: 'POST', body: JSON.stringify(b), headers }).then(r => r.json())
}

Working URLs are in streamingData.adaptiveFormats. Here is usage-example:

import { getInfo } from './yt.js'
import { writeFile } from 'fs/promises'

const info = await getInfo('C0DPdy98e4c')
const video = info.streamingData.adaptiveFormats.find(f => f.mimeType.includes('video/mp4'))
await writeFile('test.mp4', await fetch(video.url).then(async r => new Uint8Array(await r.arrayBuffer())))

konsumer avatar Jun 21 '24 02:06 konsumer

I ended up looking at yt-dlp to figure out why they do not get 403'd. I also needed to use fetch (which is built-in, now, and needed in places like cloudflare workers) instead of a http-lib. This javascript code works, without any deps:

export async function getInfo (videoId) {
  // hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py
  const apiKey = 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc'

  const headers = {
    'X-YouTube-Client-Name': '5',
    'X-YouTube-Client-Version': '19.09.3',
    Origin: 'https://www.youtube.com',
    'User-Agent': 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
    'content-type': 'application/json'
  }

  const b = {
    context: {
      client: {
        clientName: 'IOS',
        clientVersion: '19.09.3',
        deviceModel: 'iPhone14,3',
        userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
        hl: 'en',
        timeZone: 'UTC',
        utcOffsetMinutes: 0
      }
    },
    videoId,
    playbackContext: { contentPlaybackContext: { html5Preference: 'HTML5_PREF_WANTS' } },
    contentCheckOk: true,
    racyCheckOk: true
  }

  return fetch(`https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false`, { method: 'POST', body: JSON.stringify(b), headers }).then(r => r.json())
}

Working URLs are in streamingData.adaptiveFormats. Here is usage-example:

import { getInfo } from './yt.js'
import { writeFile } from 'fs/promises'

const info = await getInfo('C0DPdy98e4c')
const video = info.streamingData.adaptiveFormats.find(f => f.mimeType.includes('video/mp4'))
await writeFile('test.mp4', await fetch(video.url).then(async r => new Uint8Array(await r.arrayBuffer())))

The video from stream url has no audio output. Appears to be muted in the video player and there's no way to unmute it!

makanakidev avatar Jul 14 '24 04:07 makanakidev

The video from stream url has no audio output. Appears to be muted in the video player and there's no way to unmute it!

@makanakidev yeh, it seems to separate them. I didn't notice because my test-video is silent. It does provide audio as well, though.

This is a complete download CLI (that can also be used as library for info) that grabs the first audio & video for a format (hd1080|hd720|large|medium|small|tiny) and merges them, including progress bars and stuff. I recommend looking at how it works and customizing it to your needs.

It's also published at @konsumer/ytdownload.

konsumer avatar Jul 15 '24 06:07 konsumer

Hi everyone,

Is there a way yet to retrieve videos with audio included, similar to how it happens when sending the request with:

"context": {
    "client": {
        "clientName": "ANDROID_TESTSUITE",
        "clientVersion": "1.9"
    }
}

but being able to obtain different qualities of videos with audio included? Any guidance or updates on this would be greatly appreciated.

Thank you!

elvismdev avatar Jul 15 '24 08:07 elvismdev

@elvismdev see above. I am doing that. You need to merge the 2 streams.

konsumer avatar Jul 15 '24 22:07 konsumer

this is unusable, it works insanely slow

I ended up looking at yt-dlp to figure out why they do not get 403'd. I also needed to use fetch (which is built-in, now, and needed in places like cloudflare workers) instead of a http-lib. This javascript code works, without any deps:

export async function getInfo (videoId) {
  // hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py
  const apiKey = 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc'

  const headers = {
    'X-YouTube-Client-Name': '5',
    'X-YouTube-Client-Version': '19.09.3',
    Origin: 'https://www.youtube.com',
    'User-Agent': 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
    'content-type': 'application/json'
  }

  const b = {
    context: {
      client: {
        clientName: 'IOS',
        clientVersion: '19.09.3',
        deviceModel: 'iPhone14,3',
        userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)',
        hl: 'en',
        timeZone: 'UTC',
        utcOffsetMinutes: 0
      }
    },
    videoId,
    playbackContext: { contentPlaybackContext: { html5Preference: 'HTML5_PREF_WANTS' } },
    contentCheckOk: true,
    racyCheckOk: true
  }

  return fetch(`https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false`, { method: 'POST', body: JSON.stringify(b), headers }).then(r => r.json())
}

Working URLs are in streamingData.adaptiveFormats. Here is usage-example:

import { getInfo } from './yt.js'
import { writeFile } from 'fs/promises'

const info = await getInfo('C0DPdy98e4c')
const video = info.streamingData.adaptiveFormats.find(f => f.mimeType.includes('video/mp4'))
await writeFile('test.mp4', await fetch(video.url).then(async r => new Uint8Array(await r.arrayBuffer())))

The video from stream url has no audio output. Appears to be muted in the video player and there's no way to unmute it!

Piliponful avatar Jul 16 '24 18:07 Piliponful

this is unusable, it works insanely slow

@Piliponful It seems reasonably fast to me, but feel free to write it another way. This is a proof-of-concept. My method is the only working way to get video URLs from youtube, that I know of. If you figure it out, let the rest of us know.

konsumer avatar Jul 16 '24 23:07 konsumer

MinigetError: Status code: 403 at ClientRequest. (/opt/render/project/src/node_modules/miniget/dist/index.js:206:27) at Object.onceWrapper (node:events:633:26) at ClientRequest.emit (node:events:518:28) at HTTPParser.parserOnIncomingClient (node:_http_client:698:27) at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17) at TLSSocket.socketOnData (node:_http_client:540:22) at TLSSocket.emit (node:events:518:28) at addChunk (node:internal/streams/readable:559:12) at readableAddChunkPushByteMode (node:internal/streams/readable:510:3) at Readable.push (node:internal/streams/readable:390:5) { statusCode: 403 }

shubham-ralli avatar Jul 18 '24 11:07 shubham-ralli

i use distubejs/ytdl-core library while waiting this library fix this bug, and it work fine. Btw you guys can check this quick fix https://github.com/fent/node-ytdl-core/issues/1301#issuecomment-2223004197

import ytdl from "@distube/ytdl-core";

Namnp1521 avatar Jul 22 '24 06:07 Namnp1521

I ended up looking at yt-dlp to figure out why they do not get 403'd. I also needed to use fetch (which is built-in, now, and needed in places like cloudflare workers) instead of a http-lib. This javascript code works, without any deps:

export async function getInfo (videoId) { // hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py const apiKey = 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc'

const headers = { 'X-YouTube-Client-Name': '5', 'X-YouTube-Client-Version': '19.09.3', Origin: 'https://www.youtube.com', 'User-Agent': 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)', 'content-type': 'application/json' }

const b = { context: { client: { clientName: 'IOS', clientVersion: '19.09.3', deviceModel: 'iPhone14,3', userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)', hl: 'en', timeZone: 'UTC', utcOffsetMinutes: 0 } }, videoId, playbackContext: { contentPlaybackContext: { html5Preference: 'HTML5_PREF_WANTS' } }, contentCheckOk: true, racyCheckOk: true }

return fetch(https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false, { method: 'POST', body: JSON.stringify(b), headers }).then(r => r.json()) } Working URLs are in streamingData.adaptiveFormats. Here is usage-example:

import { getInfo } from './yt.js' import { writeFile } from 'fs/promises'

const info = await getInfo('C0DPdy98e4c') const video = info.streamingData.adaptiveFormats.find(f => f.mimeType.includes('video/mp4')) await writeFile('test.mp4', await fetch(video.url).then(async r => new Uint8Array(await r.arrayBuffer())))

This doesnt work anymore, does it?

bbmpp5 avatar Mar 01 '25 09:03 bbmpp5

I ended up looking at yt-dlp to figure out why they do not get 403'd. I also needed to use fetch (which is built-in, now, and needed in places like cloudflare workers) instead of a http-lib. This javascript code works, without any deps: export async function getInfo (videoId) { // hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py const apiKey = 'AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc' const headers = { 'X-YouTube-Client-Name': '5', 'X-YouTube-Client-Version': '19.09.3', Origin: 'https://www.youtube.com', 'User-Agent': 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)', 'content-type': 'application/json' } const b = { context: { client: { clientName: 'IOS', clientVersion: '19.09.3', deviceModel: 'iPhone14,3', userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)', hl: 'en', timeZone: 'UTC', utcOffsetMinutes: 0 } }, videoId, playbackContext: { contentPlaybackContext: { html5Preference: 'HTML5_PREF_WANTS' } }, contentCheckOk: true, racyCheckOk: true } return fetch(https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false, { method: 'POST', body: JSON.stringify(b), headers }).then(r => r.json()) } Working URLs are in streamingData.adaptiveFormats. Here is usage-example: import { getInfo } from './yt.js' import { writeFile } from 'fs/promises' const info = await getInfo('C0DPdy98e4c') const video = info.streamingData.adaptiveFormats.find(f => f.mimeType.includes('video/mp4')) await writeFile('test.mp4', await fetch(video.url).then(async r => new Uint8Array(await r.arrayBuffer())))

This doesnt work anymore, does it?

Doesn't work. I get,

status: 'LOGIN_REQUIRED',                                                                                                            
reason: 'Sign in to confirm you’re not a bot',

kethakav avatar Apr 07 '25 03:04 kethakav