Python 3, pytube, os in Windows 10
Some of my friends live in an area that really struggles to get decent internet speeds in the afternoons and evenings. So much so that they can barely watch a YouTube video at 144p some days, and that is not particularly useful if they are trying to watch a video with code or some technical specs on the screen.
They really needed to download the videos, but really did not trust the programs available online to download videos for me without spamming them with advertising or adding some malicious malware to their beloved computers.
Fortunately, someone developed a Python 3 library to do just that – pytube. In an earlier post I dive into some of the main aspects pytube:
How do I download YouTube videos with Python 3 using Pytube?
In this post, I am going to show you a quick app that can be run in the Python shell to download videos that features a progress indicator (not quite a progress bar).
I’ve intentionally kept the program fairly limited so you can focus on the important parts. I’ll show you the code and an example of what it looks like when it is running first and then give you the breakdown where you can focus on what you need to know and ignore the rest.
The Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
""" pytube 9.0.6, Python 3 Creating a simple You Tube downloader with a simple progress indicator.progress indicator. """ # sample: https://www.youtube.com/watch?v=d3D7Y_ycSms from pytube import YouTube import os # on_progress_callback takes 4 parameters. def progress_Check(stream = None, chunk = None, file_handle = None, remaining = None): #Gets the percentage of the file that has been downloaded. percent = (100*(file_size-remaining))/file_size print("{:00.0f}% downloaded".format(percent)) #Grabs the file path for Download def file_path(): home = os.path.expanduser('~') download_path = os.path.join(home, 'Downloads') return download_path def start(): print("Your video will be saved to: {}".format(file_path())) #Input yt_url = input("Copy and paste your YouTube URL here: ") print(yt_url) print ("Accessing YouTube URL...") # Searches for the video and sets up the callback to run the progress indicator. try: video = YouTube(yt_url, on_progress_callback=progress_Check) except: print("ERROR. Check your:n -connectionn -url is a YouTube urlnnTry again.") redo = start() #Get the first video type - usually the best quality. video_type = video.streams.filter(progressive = True, file_extension = "mp4").first() #Gets the title of the video title = video.title #Prepares the file for download print ("Fetching: {}...".format(title)) global file_size file_size = video_type.filesize #Starts the download process video_type.download(file_path()) print ("Ready to download another video.nn") again = start() file_size = 0 begin = start() |
The Program Running
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 17:26:49) [MSC v.1900 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. >>> RESTART: C:UsersarcherDocumentsProgrammingTrainingPythonpytubepytubeWithProgress.py Your video will be saved to: C:UsersarcherDownloads Copy and paste your YouTube URL here: cows cows Accessing YouTube URL... ERROR. Check your: -connection -url is a YouTube url Try again. Your video will be saved to: C:UsersarcherDownloads Copy and paste your YouTube URL here: https://www.youtube.com/watch?v=d3D7Y_ycSms https://www.youtube.com/watch?v=d3D7Y_ycSms Accessing YouTube URL... Fetching: archer - danger zone [hq]... 2% downloaded 4% downloaded 5% downloaded 7% downloaded 9% downloaded 11% downloaded 13% downloaded 15% downloaded 16% downloaded 18% downloaded 20% downloaded 22% downloaded 24% downloaded 26% downloaded 27% downloaded 29% downloaded 31% downloaded 33% downloaded 35% downloaded 37% downloaded 38% downloaded 40% downloaded 42% downloaded 44% downloaded 46% downloaded 48% downloaded 49% downloaded 51% downloaded 53% downloaded 55% downloaded 57% downloaded 59% downloaded 60% downloaded 62% downloaded 64% downloaded 66% downloaded 68% downloaded 70% downloaded 71% downloaded 73% downloaded 75% downloaded 77% downloaded 79% downloaded 81% downloaded 82% downloaded 84% downloaded 86% downloaded 88% downloaded 90% downloaded 92% downloaded 93% downloaded 95% downloaded 97% downloaded 99% downloaded 100% downloaded Ready to download another video. Your video will be saved to: C:UsersarcherDownloads Copy and paste your YouTube URL here: |
Step-by-Step
Imports
First, we grab the YouTube module from the pytube
library in line 9. We will also need the os
library to work with file locations (line 10).
Before we run the start function, that erh…starts the program, we will create a global variable for file_size that will change later once we have the data (line 54-55).
start
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
def start(): print("Your video will be saved to: {}".format(file_path())) #Input yt_url = input("Copy and paste your YouTube URL here: ") print(yt_url) print ("Accessing YouTube URL...") # Searches for the video and sets up the callback to run the progress indicator. try: video = YouTube(yt_url, on_progress_callback=progress_Check) except: print("ERROR. Check your:n -connectionn -url is a YouTube urlnnTry again.") redo = start() #Get the first video type - usually the best quality. video_type = video.streams.filter(progressive = True, file_extension = "mp4").first() #Gets the title of the video title = video.title #Prepares the file for download print ("Fetching: {}...".format(title)) global file_size file_size = video_type.filesize #Starts the download process video_type.download(file_path()) print ("Ready to download another video.nn") again = start() |
The start
function does the main work of running the program. On line 25 we inform the user where the file will be saved to. The curly brackets “{}” are a placeholder for whatever goes in the .format(something)
. In our case, it is the file_path
function that will find the user’s file path to their Downloads folder.
Lines 27-29 gather the YouTube URL (we hope) prints it out for the user’s reference and then informs the user why they are waiting so long.
Lines 32-36 asks pytube
to try and find the YouTube URL. It also does something special. on_progress_callback allows us to create a callback function, in our case progress_check
, that will give us some values to create our progress indicator.
We use try and except here to cover a whole variety of sins. But essentially, if the user puts in a URL that does not point to a YouTube video or just any old gibberish then the exception will be called and the whole process with start()
again. The exception might also be called if the user does not have an internet connection or even sometimes when YouTube gets sick of you running test programs and blocks you for a little while – it happened.
Next, we are evaluating the possible video types that YouTube can provide (I covered this in an earlier post here). I filter out all the possible video types by progressive and with an mp4 file extension. We take the first one of these options which will be the one with the best resolution.
I can use the video
variable that we created in line 33 to also grab the title of the video with the um…video.title
method in line 42. We then go on to print the title and inform the user that we are getting the file for download.
On line 46-47 it’s time to update the file_size
of the video that we selected by using the .filesize
method once we have decided on our video back in video_type
.
Finally, we get around to what we came here to do, download the video in line 49. While the video is downloading, callbacks will be made to help us update our progress indicator.
We then start all over again by calling the start()
function on line 52.
progress_check
12 13 14 15 16 |
# on_progress_callback takes 4 parameters. def progress_Check(stream = None, chunk = None, file_handle = None, remaining = None): #Gets the percentage of the file that has been downloaded. percent = (100*(file_size-remaining))/file_size print("{:00.0f}% downloaded".format(percent)) |
This function will take four parameters from pytube on_progress_callback
method:
stream
: the stream we chose. In our case the best resolution for an mp4 video.chunk
: the different packets of data that are downloading.file_handle
: the location the file will go in.remaining
: how many bytes remaining.
This is all gathered automatically by pytube and we don’t have to put any values in here.
For our purposes, we are going to only use the remaining
value. On line 15 we get the percentage of what has been downloaded by subtracting the file_size
by the remaining
bytes, dividing it by the file_size
and then multiplying it by 100.
This will result in a number will a large tail of decimals. We really don’t need that so I did some snazzy format
work to only show the percentage as a whole number (line 16).
progress_check
will then be called as the file downloads.
file_path
18 19 20 21 22 |
#Grabs the file path for Download def file_path(): home = os.path.expanduser('~') download_path = os.path.join(home, 'Downloads') return download_path |
In the file_path
function we look for the user’s home directory on line 20 and then join that to the Downloads so we can form the path to the user’s download file. Like this:
C:UsersarcherDownloads
There is a lot more on this in an earlier post:
How to Check a Users Home Directory for a Folder – Python 3
Conclusion
This is a very basic example. There is no option to change the download file location or to change to another file format. We could also add the option to download audio-only or download a whole playlist with the help of pytube.
Want to learn how to automate your daily admin at work with Python? Udemy has some great Python automation courses that will help you learn how to automate your tasks so you can focus on what really matters.
Got a more specific problem you need help with, but don’t have the time to develop the skills? Fiverr’s your best bet to find a skilled professional to solve your problem quickly and cheaply. *
*The above affiliate links have been carefully researched to get you to what you specifically need. If you decide to click on one of these links it will cost you just the same as going to the site. If you decide to sign up, I just get a little pocket money to help pay for the costs of running this website.
Hello, I just copied this code and it is not working now.
There is an error in function
progress_Check(stream = None, chunk = None, file_handle = None, remaining = None)
and that’s on this line:
percent = (100*(file_size-remaining))/file_size
TypeError: unsupported operand type(s) for -: ‘int’ and ‘NoneType’
file_size is set and it is an int, but remaining always remains the same (or without a value) and it gets default value – None. How to solve or just bypass it?
Thank you in advance.