0

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()
3
  • 1
    sys.stdout.write(...) likely doesn't return what you think it does. Perhaps you should save the result to a variable and then examine the variable to verify what is in it before you call text_var.set. Commented Jul 20, 2017 at 19:22
  • Hey, thanks for the answer. Still doesn't get the right output. :/ Commented Jul 20, 2017 at 20:03
  • 1
    The first step in debugging is always to validate your assumptions. Commented Jul 20, 2017 at 20:05

1 Answer 1

1

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 .
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.