Making A YouTube Video Downloader With Python’s Flask and pytube3 Libraries

How do you download YouTube videos? The easiest answer is to google sites like y2mate that work for downloading videos. But then I thought, I wonder if I can make something?

Boredom, my curiosity and some googling turned up the pytube3 library, “A lightweight, dependency-free Python 3 library (and command-line utility) for downloading YouTube Videos.” Lo and behold, 3 hours of experimentation later, I made a video downloader with Python. 😃

I used pytube3 with Flask and pythonanywhere to accomplish the task. I was pleasantly surprised at how it came together and simply worked! I’m really not that familiar with Flask either. Here’s how to make a primitive YouTube video downloader.

Install the pytube library in the pythonanywhere bash console with pip

pip3.8 install --user pytube3 --upgrade

If you’re not using pythonanywhere, install Flask (it’s already included in pythonanywhere)

python -m pip install flask

import logging
import sys
from pytube import YouTube
from flask import Flask, request, send_file

"""
Flask YouTube Video Downloader - Python Marketer
https://pythonmarketer.com/2020/10/07/making-a-youtube-video-downloader-with-pythons-flask-and-pytube3-libraries/
"""
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
app = Flask(__name__)

@app.route("/")
def youtube_downloader():
    """Render HTML form to accept YouTube URL."""
    html_page = f"""<html><head>
                    <Title>YouTube Downloader</Title></head>
                    <body><h2>Enter URL to download YouTube Vids!</h2>
                    <div class="form">
                    <form action="/download_video" method="post">
                    <input type="text" name="URL">
                    <input type="submit" value="Submit">
                    </form></div><br><br>
                    </body></html>"""
    return html_page

@app.route("/download_video", methods=["GET","POST"])
def download_video():
    """
    First pytube downloads the file locally in pythonanywhere:
    /home/your_username/video_name.mp4

    Then use Flask's send_file() to download the video 
    to the user's Downloads folder. 
    """
    try:
        youtube_url = request.form["URL"]
        download_path = YouTube(youtube_url).streams[0].download()
        fname = download_path.split("//")[-1]
        return send_file(fname, as_attachment=True)
    except:
        logging.exception("Failed download")
        return "Video download failed!"

Minimum Viable Prototype Achieved

This is more of a proof of concept than workable solution. It works for many videos I tried. It occasionally had trouble downloading certain videos. I tested it successfully on videos of up to 10 minutes. Maybe it works more consistently if the file size is smaller? Or there is a bug on certain types of videos? For me, some videos of only a few minutes failed, so your results may vary. The videos that failed returned errors like KeyError: 'cipher' and KeyError: 'url'.

Honorable Mentions

youtube-dl: Command-line program to download videos from YouTube.com and other video sites

YoutubeDownload: GUI and CLI for downloading YouTube video/audio