Hello,
To avoid freezing the GUI, I’d trying to call subprocess() in a thread… but it doesn’t work ![]()
What’s the right way to run the call in a thread, and grab the output in the GUI?
Thanks for any help.
import sys,os, wx
import subprocess
import pyperclip
import threading
def call_subprocess(URL):
TITLE = "Title not found" #default
CMD_TITLE = fr"d:\youtube-dlp.exe --no-warnings --simulate --print '%(title)s' {URL}"
p = subprocess.run(CMD_TITLE, text=True, stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
if p.returncode != 0:
output = f"ERROR TITLE: {URL}"
else:
output = p.stdout
return output
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, wx.ID_ANY,title='Bulk Youtube Download')
self.Centre()
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
panel.SetSizer(sizer)
self.label = wx.StaticText(panel, label="Title")
sizer.Add(self.label, flag=wx.ALL, border=10)
self.add_btn = wx.Button(panel, wx.ID_ANY, "Grab title")
sizer.Add(self.add_btn,0, wx.EXPAND)
self.add_btn.Bind(wx.EVT_BUTTON, self.OnAddTitleClick)
panel.Layout()
def OnAddTitleClick(self,event):
URL = pyperclip.paste()
thread1 = threading.Thread(target=call_subprocess, args=(URL,))
thread1.start()
#wait for thread to end and read output
#SyntaxError: invalid syntax
#return = thread1.join()
thread1.join()
#SyntaxError: invalid syntax
return = thread1.result
self.label.SetLabel(return)
self.sizer.Layout()
app = wx.App()
MyFrame().Show()
app.MainLoop()
–
Edit: I guess it’s an old tool?
import sys,os, wx
import subprocess
import pyperclip
#pip install thread
import thread
def call_subprocess(URL):
CMD_TITLE = fr"d:\youtube-dlp.exe --no-warnings --simulate --print '%(title)s' {URL}"
p = subprocess.run(CMD_TITLE, text=True, stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
return p.stdout if not p.returncode else f"ERROR: {URL}"
class ListBoxFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, -1,title='Bulk Youtube Download')
self.Centre()
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
self.label = wx.StaticText(panel, label="Title")
sizer.Add(self.label, flag=wx.ALL, border=10)
sizer.AddSpacer(10)
self.add_btn = wx.Button(panel, wx.ID_ANY, "Add URL")
sizer.Add(self.add_btn,0, wx.EXPAND)
self.add_btn.Bind(wx.EVT_BUTTON, self.OnAddButtonClick)
panel.SetSizer(sizer)
panel.Layout()
def onLongRunDone(output):
self.label.SetLabel(output)
def call_subprocess(URL):
CMD_TITLE = fr"c:\youtube-dlp.exe --no-warnings --simulate --print '%(title)s' {URL}"
p = subprocess.run(CMD_TITLE, text=True, stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
if p.returncode != 0:
output = f"ERROR TITLE: {URL}"
else:
output = p.stdout
return output
wx.CallAfter(self.onLongRunDone(output))
def OnAddButtonClick(self,event):
URL = pyperclip.paste()
#AttributeError: module 'thread' has no attribute 'start_new_thread'
thread.start_new_thread(call_subprocess, (URL))
self.sizer.Layout()
# self.panel.Layout() #Either works
app = wx.App()
ListBoxFrame().Show()
app.MainLoop()
–
Edit: This seems to work:
import sys,os, wx
import subprocess
import pyperclip
import _thread
class ListBoxFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, -1,title='Bulk Youtube Download')
self.Centre()
panel = wx.Panel(self, -1)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.label = wx.StaticText(panel, label="Title")
self.sizer.Add(self.label, flag=wx.ALL, border=10)
self.add_btn = wx.Button(panel, wx.ID_ANY, "Add URL")
self.sizer.Add(self.add_btn,0, wx.EXPAND)
self.add_btn.Bind(wx.EVT_BUTTON, self.OnAddButtonClick)
panel.SetSizer(self.sizer)
panel.Layout()
def onLongRunDone(self, output):
self.label.SetLabel(output)
self.sizer.Layout()
def call_subprocess(self, URL):
CMD_TITLE = fr"d:\youtube-dlp.exe --no-warnings --simulate --print '%(title)s' {URL}"
p = subprocess.run(CMD_TITLE, text=True, stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
output = p.stdout if not p.returncode else f"ERROR: {URL}"
wx.CallAfter(self.onLongRunDone,output)
def OnAddButtonClick(self,event):
URL = pyperclip.paste()
new = _thread.start_new_thread(self.call_subprocess,(URL,))
app = wx.App()
ListBoxFrame().Show()
app.MainLoop()
–
Edit: Apparently, it’s recommended in Python3 to use the “threading” module instead of “_thread”:
import threading
...
def onLongRunDone(self, output):
self.label.SetLabel(output)
def call_subprocess(self, URL):
...
self.SetTitle('Changed title in thread')
wx.CallAfter(self.onLongRunDone,output)
def OnAddButtonClick(self,event):
URL = pyperclip.paste()
x = threading.Thread(target=self.call_subprocess, args=(URL,))
x.start()