HealYouDown
HealYouDown

Reputation: 156

Python 3 - Getting realtime output of cmd in Tkinter

my goal is to get realtime output of the status from youtube-dl in shell and put it as label in tkinter. This is probably the worst way of doing this (even if it doesn't work right now), so I don't mind if someone come up with a better way to do this.

I tried a few things with another question (Getting realtime output using subprocess), but I don't get it to work.

import subprocess
import sys
import tkinter as tk
from threading import Thread

master = tk.Tk()

link = "https://www.youtube.com/watch?v=AC-3RJHzEU8"

def start_thread():
    t = Thread(target = download)
    t.start()

def download():
    global text_var
    cmd = "youtube-dl -x --audio-format mp3 {0}".format(link)

    process = subprocess.Popen(cmd,
                stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = True)

    while True:
        out = process.stdout.read(1)
        if out == '' and process.poll() != None:
            break
        if out != '':
            text_var.set(sys.stdout.write(out.decode('utf-8')))
            sys.stdout.flush()

text_var = tk.StringVar()
text_var.set("Status")
tk.Button(master, text = "Download", command = start_thread).pack()
tk.Label(master, textvariable = text_var).pack()

tk.mainloop()

Solution:

I needed to change a bit, but it worked with the answer from Dušan Atanacković. (I also used a Textwidget, because it's way better than a label)

import subprocess
import tkinter as tk
from threading import Thread

master = tk.Tk()

def sudo(cmd, terminal):

    p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1, universal_newlines=True, shell = True)
    p.poll()

    while True:
        line = p.stdout.readline()
        terminal.insert(tk.END, line)
        terminal.see(tk.END)
        if not line and p.poll is not None: break

    while True:
        err = p.stderr.readline()
        terminal.insert(tk.END, err)
        terminal.see(tk.END)
        if not err and p.poll is not None: break
    terminal.insert(tk.END, '\n Finished download')

textfield = tk.Text(master, font = "Arial 15")
textfield.pack()

link = "https://www.youtube.com/watch?v=s8XIgR5OGJc"
a = "youtube-dl --extract-audio --audio-format mp3 '{0}'".format(link)

t = Thread(target = lambda: sudo(a, textfield))
t.start()

tk.mainloop()

Upvotes: 0

Views: 1266

Answers (1)

Dušan Atanacković
Dušan Atanacković

Reputation: 444

You can solve this in two ways, first better for YT is to use pafy library, base of pafy is ytdl so it can be done since i had made that but it was slow, and i got another idea that i'am developing now, and with little modification you can connect pafys output with tkinter wodget.Second solution is

def sudo(self, cmnd, terminal, top):   # 1

        sudo_password = 'your sudo code' + '\n'
        sudos = ['sudo', '-S']

        terminal.delete('1.0', END)

        for item in eval(cmnd):
            cmd = sudos + item.split()

            p = subprocess.Popen(cmd,  stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1, universal_newlines=True)
            p.stdin.write(sudo_password)
            p.poll()

            while True:
                line = p.stdout.readline()
                terminal.insert(END, line)
                terminal.see(END)
                top.updates()
                if not line and p.poll is not None: break

            while True:
                err = p.stderr.readline()
                terminal.insert(END, err)
                terminal.see(END)
                top.updates()
                if not err and p.poll is not None: break
            terminal.insert(END, '\n * END OF PROCESS *')

cmnd - list of commands you want to execute, ['youtube-dl some link'], with even one command it should be LIST

terminal - thats Text widget in my app, but you can use any wiget as well, only you would have to change all lines terminal.insert(END, 'some text') to terminal.insert(0, 'some text') - END to 0

top is scrollbar container for my app which you can remove if you don't need it

of course you have to provide root=Tk(), parents and other containers for the terminal widget .

Upvotes: 1

Related Questions