74

There's a few posts on downloading audio from YouTube using youtube-dl, but none of them are concrete or too helpful. I'm wondering what the best way to do it from a Python script is.

For example, here's the README example for downloading videos:

import youtube_dl

ydl_opts = {}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
    ydl.download(['http://www.youtube.com/watch?v=BaW_jenozKc'])

Obviously if you just care about the audio, you'd rather not download the whole video...

Therefore, the youtube-dl source isn't very helpful

Any suggestions on how to script this?

noobie
  • 57
  • 2
  • 9
lollercoaster
  • 15,969
  • 35
  • 115
  • 173

5 Answers5

110

Read on in the developer instructions for an amended example:

from __future__ import unicode_literals
import youtube_dl


ydl_opts = {
    'format': 'bestaudio/best',
    'postprocessors': [{
        'key': 'FFmpegExtractAudio',
        'preferredcodec': 'mp3',
        'preferredquality': '192',
    }],
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
    ydl.download(['http://www.youtube.com/watch?v=BaW_jenozKc'])

This will download an audio file if possible/supported. If the file is not mp3 already, the downloaded file be converted to mp3 using ffmpeg or avconv. For more information, refer to the format and postprocessors documentation entries in a current version of youtube-dl.

  • 1
    Ive tried the above but get the following error: ERROR: audio conversion failed: file:mp3: Invalid argument. If i try using 'best' instead of mp3 i get the same error but for file:opus instead. I am able to use the youtube-dl command line tool fine, but when executed in python i cant seem to get the postprocessor bit to work. Any ideas? – stackPusher Sep 22 '16 at 16:58
  • @stackPusher That sounds like a problem with ffmpeg, avconv. Please post a new question, and do include your entire demo program (the one you actually run, can be identical to this answer) as well as the entire output when you activate verbose - the first line should be along the lines of `[debug] System config: []`. –  Sep 22 '16 at 20:34
  • Thanks I posted a new question with the details: http://stackoverflow.com/questions/39665160/youtube-dl-python-script-postprocessing-error-ffmpeg-codecs-arent-being-recogn . If youd like me to delete my comments from this post just say the word. thanks! – stackPusher Sep 23 '16 at 16:07
  • @phihag how to make your script avoid any post-processing? (that is, download in the same format as it is originally in youtube to avoid re-encodings) – knocte Nov 11 '16 at 16:29
  • @knocte Have you tried removing the postprocessors by setting `postprocessors` to `[]`? –  Nov 11 '16 at 17:38
  • mmm, I guess the result of that would be the same as simply issuing `./youtube-dl --extract-audio --format bestaudio https://www.youtube.com/watch?v=3LZugKYOx80` from the command line? – knocte Nov 11 '16 at 17:46
  • @knocte No, `--extract-audio` implies postprocessors. –  Nov 11 '16 at 19:19
  • @knocte If the chosen `--audio-format` does not match the downloaded file, there will certainly be re-encoding. Even if it does match, there may be some (lossless) re-encoding, because not all video services always serve good files. –  Nov 12 '16 at 07:50
  • but using `bestaudio` format keyword would always match, right? – knocte Nov 12 '16 at 07:52
  • If `--audio-format` has an effective value of `best`, I believe so. Instead of speculating, if you just want the downloaded file, and don't want it to be touched, simply do **not** pass in `--extract-audio`. –  Nov 12 '16 at 07:56
  • I want it to be touched, but only for extracting (removing the video) without reencoding the audio! I mean, if the audio is already lossless, I don't want reencodings because the audio would lose quality even more – knocte Nov 13 '16 at 09:37
  • @knocte Maybe ask a new question. You seem to be confused on what you actually want to do. When you pass in `-f bestaudio`, you are downloading an audio file, there is no video to extract. `--extract-audio -f bestaudio` only makes sense if you want to reencode to another format. With `--audio-format best` (the default) there is (I believe in all cases) no loss of quality. Have you actually tried running `youtube-dl -x ...`? That should just work and not lose any quality. –  Nov 13 '16 at 12:25
  • I've tried `-f bestaudio` but sometimes it downloads a `.webm`, but if I use both `--extract-audio -f bestaudio` seems to work alright, by extracting the .opus file from the .webm container – knocte Nov 13 '16 at 12:32
  • On OS X you ma face error like `ffprobe or avprobe not found. Please install one ` you fix it with `brew install libav` – andilabs May 24 '19 at 10:22
  • is there a way to download a part on the video – Walid Bousseta Aug 11 '21 at 16:03
  • I was wondering if there is any way to speed up video to audio conversion? – Yalchin Mammadli Mar 20 '22 at 16:36
16

Use postprocessors argument. The list of all the available postprocessors can be found here.

If you want to pass additional ffmpeg or avconv options, which are not included in youtube-dl library (like audio bitrate - -ar <BR> in ffmpeg), add postprocessor_args as a list.

You can also prefer ffmpeg over avconv setting prefer_ffmpeg to True.

And to keep both original and converted audio file set 'keepvideo' to True.

For example:

from __future__ import unicode_literals
import youtube_dl

ydl_opts = {
    'format': 'bestaudio/best',
    'postprocessors': [{
        'key': 'FFmpegExtractAudio',
        'preferredcodec': 'wav',
        'preferredquality': '192'
    }],
    'postprocessor_args': [
        '-ar', '16000'
    ],
    'prefer_ffmpeg': True,
    'keepvideo': True
}

with youtube_dl.YoutubeDL(ydl_opts) as ydl:
    ydl.download(['http://www.youtube.com/watch?v=BaW_jenozKc'])

The list of all the available options is in the documentation. You can read ffmpeg posprocessor's code here.

And a less complex example is in their GitHub README.

Pheon
  • 161
  • 1
  • 4
  • Note: If you let go of re-sampling `postprocessor_args` like `-ar` and your `preferredcodec` is the actual file codec as stated by `ffprobe` and one of `aac`, `flac`, `mp3`, `vorbis` or `opus`, then the `acodec` is `copy` / the re-encoding is automatically skipped and you save a ton of cpu-ressources. [See here.](https://github.com/ytdl-org/youtube-dl/blob/3a7ef27cf306a0a8f79ebd78ae60329c53080d14/youtube_dl/postprocessor/ffmpeg.py#L280) E.g. `ydl_opts = { 'format': '250', 'postprocessors': [{'key': 'FFmpegExtractAudio','preferredcodec': 'opus'}]}` – Suuuehgi Jun 28 '21 at 10:06
12

I did not intend to answer this question, in fact, I came to find an answer for myself. In my search, none of these answers worked in a satisfactory manner. I did however find an excellent alternative that worked perfectly for me that I felt I should share: the module pytube.

from pytube import YouTube
import os

yt = YouTube('YOUR LINK HERE')

video = yt.streams.filter(only_audio=True).first()

out_file = video.download(output_path=".")

base, ext = os.path.splitext(out_file)
new_file = base + '.mp3'
os.rename(out_file, new_file)
Matt
  • 225
  • 2
  • 9
  • Just adding some more knowledge I've gained since originally writing this: the last 3 lines will not reliably change the filetype from mp4. It changes it so it's just the audio, for sure, but its still an mp4 file. To truly and reliably change the filetype to MP3, you will have to make use of something like FFMPEG, which has worked quite nicely for me, but can be somewhat janky. – Matt Dec 23 '22 at 22:43
  • note as well youtube doesn't like this sort of thing so in the current version (15.0.0) you will have to remove the semicolon in line 287 of cipher.py within the package for it to work (see threads related to get throttling function name mismatch for multiple error) – Matt Jul 12 '23 at 03:13
2

As youtube_dl is discontinued, you can use tube_dl

Usage :

pip install tube_dl
from tube_dl import Youtube

In your case, here's how to get only audio.

from tube_dl import Youtube
youtube('Your URL').formats.filter(only_audio=True)[0]**.download(convert='mp3')

** Instead of 0, you can use your favourite quality. Just type:

print(youtube('Your URL').formats.filter(only_audio=True))

This will print all the audios supported. Then specify index of your choice and download

EDIT:

filter is deprecated, use filter_by instead

cracksii
  • 60
  • 9
shekhar chander
  • 600
  • 8
  • 14
  • Hi, I'd just like to let you know that as of 09/29/'21 this appears to download corrupt files which cannot be opened. it also requires you to pip install a variety of other modules such as moviepy and eyed3 – Matt Sep 29 '21 at 22:09
  • @Matt The moviepy is needed to convert files to audio and eyed3 is there to add metadata to the audio file. And about the corrupted file, you can raise the issue on github. https://github.com/shekharchander/tube_dl/ – shekhar chander Sep 30 '21 at 10:50
1

Although this post has not been modified for a long time, I've been working on it lately and built a GUI in python. There you can enter a yt link or a name and the corresponding audio will be downloaded.

https://github.com/JacobTh98/yt2audio.git
JaTh98
  • 11
  • 2
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/34012298) – eschibli Mar 16 '23 at 18:47