Reputation: 89
I am trying to make a downloader with a progress bar for youtube videos using pytube, but I am stuck on an error.
My code:
from pytube import YouTube
def on_progress(stream, chunk, bytes_remaining):
total_size = stream.filesize
bytes_downloaded = total_size - bytes_remaining
percentage_of_completion = bytes_downloaded / total_size * 100
print(percentage_of_completion)
url = "https://www.youtube.com/wat
ch?v=XQZgdHfAAjI&list=PLec973iciX1S0bLNOdmIejMVnUnBWpIwz"
yt_obj = YouTube(url).register_on_progress_callback(on_progress)
stream = yt_obj.streams.filter(progressive=True).get_highest_resolution().download()
size = stream.filesize
print(f"file size is {size}")
When I run this code, I get the following error:
Traceback (most recent call last):
File "pytube_progress.py", line 15, in <module>
stream = yt_obj.streams.filter(progressive=True).get_highest_resolution().download()
AttributeError: 'NoneType' object has no attribute 'streams'
Interestingly, when I replace this line of code: yt_obj = YouTube(url).register_on_progress_callback(on_progress)
with yt_obj = YouTube(url)
every thing works fine, and there are no errors.
Documentation for the register_on_progress_callback()
function can be found here.
Upvotes: 1
Views: 2115
Reputation: 4750
The first problem in your code is, when the line
yt_obj = YouTube(url).register_on_progress_callback(on_progress)
is executed, since the register_on_progress_callback()
function doesn't return anything, the variable yt_obj
is assigned the value None
. Then, when you have yt_obj.streams
later in your code, that triggers the AttributeError
.
The second problem is with this line:
stream = yt_obj.streams.filter(progressive=True).get_highest_resolution().download()
The download()
function returns a str
, not a Stream
.
Here is a working version of your code, with these two problems fixed:
from pytube import YouTube
def on_progress(stream, chunk, bytes_remaining):
total_size = stream.filesize
bytes_downloaded = total_size - bytes_remaining
percentage_of_completion = bytes_downloaded / total_size * 100
print(percentage_of_completion)
url = "https://www.youtube.com/watch?v=XQZgdHfAAjI&list=PLec973iciX1S0bLNOdmIejMVnUnBWpIwz"
# Create the YouTube object first
yt_obj = YouTube(url)
# Then register the callback
yt_obj.register_on_progress_callback(on_progress)
# Download the video, getting back the file path the video was downloaded to
file_path = yt_obj.streams.filter(progressive=True).get_highest_resolution().download()
print(f"file_path is {file_path}")
Upvotes: 4
Reputation: 417
This would work as well, note you'll just get progress bar once, as 2nd time you run the script you will already have the file downloaded.
from pytube.cli import on_progress
from pytube import YouTube
url = "https://www.youtube.com/watch?v=DkU9WFj8sYo"
print("\n")
try:
yt = YouTube(url, on_progress_callback=on_progress)
yt.streams\
.filter(file_extension='mp4')\
.get_highest_resolution()\
.download()
except EOFError as err:
print(err)
else:
print("\n====== Done - Check Download Dir =======")
Upvotes: 2