Search code examples
pythonyoutubepytube

Pytube progress only shows 99 and 100


I am trying to show progress in pytube while its downloading a video. but it only shows 99 and 100, and then Completed.

Here is my code:

from pytube import YouTube
import os

max_file_size = 0

def on_progress(stream, data_chunk, bytes_remaining):
    percent = int(100 - (100 * (bytes_remaining/max_file_size)))
    print(percent)

def on_comp(stream, path):
    print('Completed')

yt = YouTube('https://www.youtube.com/watch?v=qxYbHzn8bbU&t=84s', 
    on_progress_callback=on_progress, on_complete_callback=on_comp)       
video = yt.streams.first()
max_file_size = video.filesize
video.download(os.getcwd())

Output:

99
100
Completed

Thanks!


Solution

  • Digging in source code I found in pytube.request line

    default_range_size = 9437184  # 9MB
    

    which is used as chunk size in lines

    stop_pos = min(downloaded + default_range_size, file_size) - 1
    range_header = f"bytes={downloaded}-{stop_pos}"
    

    so it download 9MB in one chunk.

    You download file which has only ~9MB so it downloads almost all in one chunk and it can display only 99% or 100%.

    If you try with longer file using

    video = yt.streams[2] 
    # or 
    video = yt.streams.get_by_itag(22)
    # or
    video = yt.streams.get_highest_resolution()
    

    then it will download ~45MB and it will display 20%, 40%, 60%, 80%, 100%


    Maybe if you could change default_range_size into smaller value then it will display percent for smaller files too - but I think it would need to change it directly in source code, so you can't do it in easy way.


    Minimal working code - with other small changes.

    I use

    • f'{percent:.0%}' to display 0.20 as 20% so I don't have to calculate it as on my own,
    • f'{max_file_size:_}' to display size as 104_465_890 instead of 104465890,
    • end='\r' to display percent in in the same line and replace previous value.
    from pytube import YouTube
    
    def on_progress(stream, data_chunk, bytes_remaining):
        #print('bytes_remaining:', bytes_remaining)
        downloaded = max_file_size - bytes_remaining
        percent = downloaded/max_file_size
        print(f'Downloaded: {percent:.0%}', end='\r')
    
    def on_complete(stream, path):
        print('Completed:', path)
    
    # --- main ---
    
    url = 'https://www.youtube.com/watch?v=aqz-KE-bpKQ'  # "Big Buck Bunny" ~100MB
    #url = 'https://www.youtube.com/watch?v=qxYbHzn8bbU' # ~45MB
    
    yt = YouTube(url,
                 on_progress_callback=on_progress,
                 on_complete_callback=on_complete)
    
    #for item in yt.streams:
    #    print(item)
    
    #video = yt.streams[2]
    #video = yt.streams.get_by_itag(22)
    video = yt.streams.get_highest_resolution()
    
    max_file_size = video.filesize
    print(f'Size: {max_file_size:_} bytes')
    
    video.download(skip_existing=False)