I've been programming a small project in python to practice gui, however I'm a bit stuck in this part of handling a gtk progress bar. I think the problem is related to yt-dlp blocking the main thread when starting the download, or because gtk doesn't allow another thread to modify its own element. This is my code:
window.py
from downloader.download import Downloader
from time import sleep
import gi
import threading
# from multiprocessing import Process
from db.database import Data
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
class ProgressUpdate(threading.Thread):
def __init__(self, progress_bar, downloader):
super().__init__()
self.progress_bar = progress_bar
self.downloader = downloader
self.is_running = True
def stop(self):
self.is_running = False
def run(self):
while self.is_running:
percent = self.downloader.percent
print('Percent', percent)
if percent and percent != 0:
GLib.idle_add(self._update_progres_bar, percent)
sleep(0.5)
def _update_progress_bar(self, percent):
self.progress_bar.set_fraction(percent)
return False
class Window(Gtk.Window):
def __init__(self):
super().__init__(title="Downloader")
self.notebook = Gtk.Notebook()
self.add(self.notebook)
# Init conection with database
self.data = Data()
self.data.create_connection()
# Display page of window
self.display_download()
self.display_history()
self.link = ''
...
# more code
...
# callback function called when 'download' button is pressed
def __on_button_clicked(self, widget):
# Process for download
link = self.download_entry.get_text()
if link != "":
self.progress_bar.set_fraction(0)
downloader = Downloader()
updater = ProgressUpdate(self.progress_bar, downloader)
updater.start()
downloader.download(link) # Using yt-dlp
updater.stop()
self.progress_bar.set_fraction(1)
downloader.py
import yt_dlp as dl
# import os
LINK = ''
class Downloader:
def __init__(self):
self.status = ''
self.percent = None
# Clean percent value
def __clean_percent(self, percent):
for i, char in enumerate(percent):
if char == '%':
value = percent[i-5:i+1].replace('%', '')
break
try:
value = (float(value.replace(' ', '')) / 100)
except Exception as e:
print(e)
return value
def my_hook(self, d):
if d['status'] == 'downloading':
self.percent = self.__clean_percent(d['_percent_str'])
elif d['status'] == 'finished':
self.status = 'finished'
def download(self, link=LINK):
opts = {
'progress_hooks': [self.my_hook],
}
with dl.YoutubeDL(opts) as ytdl:
ytdl.download([link])
if __name__ == '__main__':
d = Downloader()
d.download()
I would just like to update the progress bar with the download percentage.
A gtk4 version based in your code and this documentation about threads on gtk https://pygobject.readthedocs.io/en/latest/guide/threading.html