2017-07-20 84 views
0

我的目標是從shell中的youtube-dl獲得狀態的實時輸出,並將其作爲tkinter中的標籤。這可能是這樣做的最糟糕的方式(即使它現在不工作),所以我不介意有人想出一個更好的方法來做到這一點。Python 3 - 在Tkinter中獲取cmd的實時輸出

我用另一個問題嘗試了幾件事(Getting realtime output using subprocess),但我沒有得到它的工作。

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

解決方法:

我需要改變了一點,但它與杜尚Atanackovic的答案工作。 (我也用了Textwidget,因爲它的方式比標籤更好)

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

'sys.stdout.write函數(...)「可能不會返回您認爲它所做的事情。也許你應該將結果保存到一個變量中,然後在調用'text_var.set'之前檢查該變量以驗證其中的內容。 –

+0

嘿,謝謝你的回答。仍然沒有得到正確的輸出。 :/ – HealYouDown

+1

調試的第一步總是驗證您的假設。 –

回答

1

您可以通過兩種方式,一是爲YT較好地解決,這是使用pafy庫,pafy的基礎是ytdl因此它可以做到因爲我做了這一點,但它很慢,我得到了另一種想法,我'現在開發,並與稍加修改就可以用Tkinter的wodget.Second解決方案連接pafys輸出

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 .