fent / node-ytdl-core

YouTube video downloader in javascript.
MIT License
4.46k stars 784 forks source link

MinigetError: Status code: 403 #1289

Open Namnp1521 opened 3 months ago

Namnp1521 commented 3 months ago

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"

shubham110019 commented 3 months ago

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

shubham110019 commented 3 months ago

Is there any update

mdanish1326 commented 2 months ago

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

konsumer commented 2 months ago

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())))
makanakidev commented 1 month ago

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!

konsumer commented 1 month ago

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.

elvismdev commented 1 month ago

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!

konsumer commented 1 month ago

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

Piliponful commented 1 month ago

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!

konsumer commented 1 month ago

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.

shubham110019 commented 1 month ago

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 }

Namnp1521 commented 1 month ago

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";