“如何使用yt-dlp api提供的下载百分比更新PyGtk中的进度条?”

"How to update a progress bar in PyGtk with the download percentage provided by the yt-dlp api?"

提问人:Nahuel Aguirre 提问时间:4/8/2023 更新时间:4/14/2023 访问量:120

问:

我一直在用 python 编写一个小项目来练习 gui,但是我有点卡在处理 gtk 进度条的这一部分。 我认为问题与 yt-dlp 在开始下载时阻塞主线程有关,或者因为 gtk 不允许另一个线程修改自己的元素。 这是我的代码:

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()

我只想用下载百分比更新进度条。

蟒蛇 gtk pygtk youtube-dl

评论


答:

0赞 Gonzalo Odiard 4/14/2023 #1

基于您的代码的 gtk4 版本和有关 gtk https://pygobject.readthedocs.io/en/latest/guide/threading.html 上线程的文档

import threading
import time
import gi

import yt_dlp as dl


gi.require_version('Gtk', '4.0')
from gi.repository import GLib, Gtk, GObject


class Application(Gtk.Application):

    def do_activate(self):
        window = Gtk.ApplicationWindow(application=self)
        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        self.entry = Gtk.Entry()
        self.box.append(self.entry)

        self.button = Gtk.Button(label='Download')
        self.button.connect('clicked', self.start)
        self.box.append(self.button)

        self.progress = Gtk.ProgressBar(show_text=True)
        self.box.append(self.progress)

        window.set_child(self.box)
        window.present()

    def update_progess(self, i):
        self.progress.set_fraction(i)
        return False

    def dl_update_hook(self, dl):
        percent = dl['_percent_str']
        for i, char in enumerate(percent):
            if char == '%':
                value = percent[i-5:i+1].replace('%', '')
                break
        value = (float(value.replace(' ', '')) / 100)
        GLib.idle_add(self.update_progess, value)

    def start_download(self):
        opts = {'progress_hooks': [self.dl_update_hook]}
        url = self.entry.get_text()
        with dl.YoutubeDL(opts) as ytdl:
            ytdl.download([url])


    def start(self, button):
        print('Start!')
        thread = threading.Thread(target=self.start_download)
        thread.daemon = True
        thread.start()


app = Application()
app.run()