-1

The progress bar in the below code is never updated, and for the method show_progress, the code starting from the if statement also never runs. I need to update the progress bar and the label downloading_progress_value whenever the download starts, and stop the progress bar when the download finishes. Can anyone show me where is the mistake?

Note: I removed some controls for simplicity. Python version: 3.7 and Pytube version: 9.6.4

import threading
from tkinter import *
from tkinter import messagebox as mbox
from tkinter import ttk

from pytube import YouTube


class Application:
    def __init__(self, root):
        self.root = root
        self.video_url = "https://www.youtube.com/watch?v=fjHW5kBvonY"

        ########################### This label used to show the progress when download starts  ###########################
        self.downloading_progress_value = StringVar()
        self.downloading_progress = Label(self.root, text=" ", textvariable=self.downloading_progress_value)
        self.downloading_progress.place(x=114, y=190)

        self.progress_bar = ttk.Progressbar(self.root,orient=HORIZONTAL, length=425, mode="determinate")
        self.progress_bar.place(x=114, y=215)

    ########################### starting the dowload  ###########################
    def start_download(self):
        self.app_download = DownloadApp(self.progress_bar, self.video_url.get(), self.folder_name,
                                        self.choices_var.get(), self.downloading_progress_value)

    ########################### the class responsible for downloading operations  ###########################
class DownloadApp:
    def __init__(self, progress_bar, youtube_url, media_folder, media_choice, downloading_progress_value):
        self.progress_bar = progress_bar
        self.youtube_url = youtube_url
        self.media_folder = media_folder
        self.media_choice = media_choice
        self.downloading_progress_value = downloading_progress_value

        self.youtube = YouTube(url=youtube_url)
        if self.media_choice == "1":
            self.youtube_stream = self.youtube.streams.filter(progressive=True, file_extension="mp4").order_by('resolution').desc().first()
            self.youtube_stream.download(output_path=self.media_folder, filename=self.youtube_stream.title)
            self.max_file_size = self.youtube_stream.filesize

        if self.media_choice == "2":
            self.youtube_stream = self.youtube.streams.filter(only_audio=True, file_extension="webm").first()
            self.youtube_stream.download(output_path=self.media_folder, filename=self.youtube_stream.title)
            self.max_file_size = self.youtube_stream.filesize

        self.downloading_progress_value.set("Downloading is in progress....")
        threading.Thread(target=self.youtube.register_on_progress_callback(self.show_progress)).start()
        threading.Thread(target=self.download_file).start()

    def show_progress(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):
        self.percent_count = float("%.2f" (100 - ( 100 * (bytes_remaining /self.max_file_size))))
        mbox.showinfo("Test 1", "test the method 1")
        print(self.percent_count)
        if self.percent_count < 100:
            self.downloading_progress_value.set(str(self.percent_count))
            self.progress_bar['value'] = self.percent_count
        else:
            self.progress_bar.stop()
            self.downloading_progress_value.grid_forget()
            self.progress_bar.grid_forget()
        mbox.showinfo("Test 2", "test the method 2")

    def download_file(self):
        if self.media_choice == "1":
            self.youtube_stream = self.youtube.streams.filter(progressive=True, file_extension="mp4").order_by('resolution').desc().first().download(output_path=self.media_folder, filename=self.youtube_stream.title)
        if self.media_choice == "2":
            self.youtube_stream = self.youtube.streams.filter(only_audio=True, file_extension="webm").first().download(output_path=self.media_folder, filename=self.youtube_stream.title)
        mbox.showinfo("Download Finished", "Video downloaded successfully")


if __name__ == "__main__":
    window = Tk()
    window.title("Youtube Downloader")
    window.geometry("1020x550+400+210")
    window.resizable(0, 0)

    app = Application(window)
    mainloop()
  • 2
    There are _lots_ of questions on this site related to a progress bar not updating. Have you researched any of them? – Bryan Oakley Oct 26 '20 at 18:41
  • yes and couldn't solve my issue. – MoAbdelghani Oct 26 '20 at 19:15
  • Please try to reduce the code down to a [mcve]. As written, there's a lot of code that seems unrelated to the problem you're trying to solve. – Bryan Oakley Oct 26 '20 at 19:16
  • code reduced, only reproducible code exist. – MoAbdelghani Oct 26 '20 at 19:24
  • Not really into threading, but from what I can see you never seem to set `bytes_remaining` to any value except for the default = `None`. – figbeam Oct 26 '20 at 20:35
  • @figbeam Initialized with `None` but it's registered for callback function as mentioned in pytube api, [pytube api](https://python-pytube.readthedocs.io/en/latest/api.html#pytube.YouTube.register_on_progress_callback) – MoAbdelghani Oct 26 '20 at 20:49
  • Is this [problem-with-on-progress-callback-of-python-module-pytube](https://stackoverflow.com/questions/64417119/problem-with-on-progress-callback-of-python-module-pytube) help? – acw1668 Oct 27 '20 at 01:23

2 Answers2

0

Getting an error for the string conversion in show_progress().

percent_count = float("%.2f" % (100 - ( 100 * (bytes_remaining/max_file_size))))
# missing -------------------^

Are you getting this error? Or does it work? If so, what values do you get from the conversion?

figbeam
  • 7,001
  • 2
  • 12
  • 18
  • I tried some of your answers but the pytube library has raised many issues, so I've used another one and everything worked fine with some tweaks. thanks all for your replies and answers. – MoAbdelghani Nov 04 '20 at 10:28
0
def show_progress(self, stream=None, chunk=None, file_handle=None, bytes_remaining=None):

The show_progress() function should only take 3 arguments - stream, chunk and bytes_remaining, in that order. The way you have done it, pytube passes the bytes_remaining argument to the file_handle parameter.

Also I think you should put a '%' character before the expression which calculates percent_count, like this -

self.percent_count = float("%.2f" %(100 - ( 100 * (bytes_remaining /self.max_file_size))))

Please do tell if this fixes the problem or not.

Edit: Also another thing I noted, your DownloadApp class's init method actually downloads the file even before you register the on_progress_callback or call the download_file() method. This not only implies that your progress callback won't be called during the first download, but also ensures that it won't be called during the second time either(as pytube skips the download if file already exists).