如何在使用 pytube 时停止不响应 tkinter?
How to stop not responding tkinter whilst using pytube?
我创建了一个下载 audio/video 的 tkinter 应用程序。它确实工作正常,但是(在这里猜测)因为下载需要 5-10 秒,它会阻塞主循环并导致它说在完成之前没有响应,这不是很好。我知道可以使用线程,但我从未真正使用过它,而且我尝试过的所有示例都无法正常工作。
这是我的完整代码,没有线程:(如果太长而无法阅读,我将只展示某些功能,这可能是
from tkinter import *
from tkinter import messagebox
from pytube import YouTube
import sys, os, threading, time
def btn_clicked():
print("Button Clicked")
window = Tk()
window.geometry("505x187")
window.title("Youtube Video Downloader")
photo = PhotoImage(file = "icon.png")
window.iconphoto(False, photo)
window.configure(bg = "#3d3d3d")
canvas = Canvas(
window,
bg = "#3d3d3d",
height = 187,
width = 505,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
def round_rectangle(x1, y1, x2, y2, radius=25, **kwargs):
points = [x1+radius, y1,
x1+radius, y1,
x2-radius, y1,
x2-radius, y1,
x2, y1,
x2, y1+radius,
x2, y1+radius,
x2, y2-radius,
x2, y2-radius,
x2, y2,
x2-radius, y2,
x2-radius, y2,
x1+radius, y2,
x1+radius, y2,
x1, y2,
x1, y2-radius,
x1, y2-radius,
x1, y1+radius,
x1, y1+radius,
x1, y1]
return canvas.create_polygon(points, **kwargs, smooth=True)
radius = 10
olw = 1
ft = None
ebl = []
eb = round_rectangle(
320, 37, 320+174, 37+51,
fill = "#212121",
radius = radius,
outline = "")
ebl.append(eb)
dl = []
d = round_rectangle(
320, 135, 320+174, 135+43,
fill = "#212121",
radius = radius,
outline = "")
dl.append(d)
dt = canvas.create_text(
370, 148,
text = "DOWNLOAD",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
dl.append(dt)
mptl = []
mpt = round_rectangle(
320, 97, 320+82, 97+31,
fill = "#212121",
radius = radius,
outline = "")
mptl.append(mpt)
mpfl = []
mpf = round_rectangle(
412, 97, 412+82, 97+31,
fill = "#212121",
radius = radius,
outline = "")
mpfl.append(mpf)
pb = my_rectangle = round_rectangle(
11, 10, 11+300, 10+168,
fill = "#212121",
radius = radius,
outline = "")
ebt = canvas.create_text(
326, 43,
text = "Video URL:",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(13.0) - 5))
ebl.append(ebt)
mptt = canvas.create_text(
348, 103,
text = "MP3",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
mptl.append(mptt)
mpft = canvas.create_text(
440, 103,
text = "MP4",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
mpfl.append(mpft)
canvas.create_text(
320, 13,
text = "Youtube Video Downloader",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(15.0) - 5))
entry0_img = PhotoImage(file = f"img_textBox0.png")
entry0_bg = canvas.create_image(
406.0, 70.5,
image = entry0_img)
ebf = Entry(
bd = 0,
bg = "#212121",
fg = "#727272",
insertbackground = "#727272",
highlightthickness = 0)
ebf.place(
x = 326, y = 61,
width = 160,
height = 17)
def OnHover(item):
if item in mptl or mpfl:
if canvas.itemcget(item, "outline") == "":
if canvas.itemcget(item, "tag") == "clickset":
pass
else:
canvas.itemconfig(item, outline="#FF7276", width = olw, tag="hoverset")
else:
pass
def UnHover(item):
if item in mptl or mpfl:
if canvas.itemcget(item, "tag") == "hoverset":
canvas.itemconfig(item, outline="", width = olw, tag="")
else:
pass
def bindhover(l, item):
for i in l:
canvas.tag_bind(i, '<Enter>', lambda event: OnHover(item=item))
canvas.tag_bind(i, '<Leave>', lambda event: UnHover(item=item))
bindhover(mptl, mpt)
bindhover(mpfl, mpf)
bindhover(dl, d)
def OnClick(item):
global ft
if item in mptl or mpfl:
if canvas.itemcget(item, "tag") == "hoverset":
if item == mpt:
if canvas.itemcget(mpf, "outline") == "":
ft = "mp3"
else:
canvas.itemconfig(mpf, outline="")
ft = "mp3"
if item == mpf:
if canvas.itemcget(mpt, "outline") == "":
ft = "mp4"
else:
canvas.itemconfig(mpt, outline="")
ft = "mp4"
canvas.itemconfig(item, tag="clickset")
else:
pass
def bindclick(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: OnClick(item=item))
bindclick(mptl, mpt)
bindclick(mpfl, mpf)
def download():
e = False
link = ebf.get()
try:
link2 = YouTube(link)
except:
messagebox.showinfo("Invalid link", "Invalid youtube link")
e = True
if e == False:
if ft == None:
messagebox.showinfo("Select a file type", "No file type has been selected")
e = True
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
vid = video.download('Downloads')
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
else:
if e == False:
video = link2.streams.first()
vid = video.download('Downloads')
else:
pass
def bdownload(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: download())
bdownload(dl, d)
window.resizable(False, False)
window.mainloop()
下载:
def download():
e = False
link = ebf.get()
try:
link2 = YouTube(link)
except:
messagebox.showinfo("Invalid link", "Invalid youtube link")
e = True
if e == False:
if ft == None:
messagebox.showinfo("Select a file type", "No file type has been selected")
e = True
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
vid = video.download('Downloads')
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
else:
if e == False:
video = link2.streams.first()
vid = video.download('Downloads')
else:
pass
def bdownload(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: download())
bdownload(dl, d)
只是想知道如何将其放入线程中?
开始新话题的格式为:
new_thread = threading.Thread(target=..., daemon=True, args=(..., ...))
new_thread.start()
所以试试这个:
def download_worker(player, ft):
vid = video.download('Downloads')
if ft == "mp3":
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
def download():
...
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
# Imagine this like: download_worker(video, ft)
new_thread = threading.Thread(target=download_worker, daemon=True, args=(video, ft))
new_thread.start()
else:
if e == False:
video = link2.streams.first()
# Imagine this like: download_worker(video, ft)
new_thread = threading.Thread(target=download_worker, daemon=True, args=(video, ft))
new_thread.start()
# Keep in mind that the `vid` variable doesn't exist here.
在这种情况下,目标函数是 download_worker
,参数是:video
和 ft
。
线程在目标函数结束时自动结束。
我创建了一个下载 audio/video 的 tkinter 应用程序。它确实工作正常,但是(在这里猜测)因为下载需要 5-10 秒,它会阻塞主循环并导致它说在完成之前没有响应,这不是很好。我知道可以使用线程,但我从未真正使用过它,而且我尝试过的所有示例都无法正常工作。
这是我的完整代码,没有线程:(如果太长而无法阅读,我将只展示某些功能,这可能是
from tkinter import *
from tkinter import messagebox
from pytube import YouTube
import sys, os, threading, time
def btn_clicked():
print("Button Clicked")
window = Tk()
window.geometry("505x187")
window.title("Youtube Video Downloader")
photo = PhotoImage(file = "icon.png")
window.iconphoto(False, photo)
window.configure(bg = "#3d3d3d")
canvas = Canvas(
window,
bg = "#3d3d3d",
height = 187,
width = 505,
bd = 0,
highlightthickness = 0,
relief = "ridge")
canvas.place(x = 0, y = 0)
def round_rectangle(x1, y1, x2, y2, radius=25, **kwargs):
points = [x1+radius, y1,
x1+radius, y1,
x2-radius, y1,
x2-radius, y1,
x2, y1,
x2, y1+radius,
x2, y1+radius,
x2, y2-radius,
x2, y2-radius,
x2, y2,
x2-radius, y2,
x2-radius, y2,
x1+radius, y2,
x1+radius, y2,
x1, y2,
x1, y2-radius,
x1, y2-radius,
x1, y1+radius,
x1, y1+radius,
x1, y1]
return canvas.create_polygon(points, **kwargs, smooth=True)
radius = 10
olw = 1
ft = None
ebl = []
eb = round_rectangle(
320, 37, 320+174, 37+51,
fill = "#212121",
radius = radius,
outline = "")
ebl.append(eb)
dl = []
d = round_rectangle(
320, 135, 320+174, 135+43,
fill = "#212121",
radius = radius,
outline = "")
dl.append(d)
dt = canvas.create_text(
370, 148,
text = "DOWNLOAD",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
dl.append(dt)
mptl = []
mpt = round_rectangle(
320, 97, 320+82, 97+31,
fill = "#212121",
radius = radius,
outline = "")
mptl.append(mpt)
mpfl = []
mpf = round_rectangle(
412, 97, 412+82, 97+31,
fill = "#212121",
radius = radius,
outline = "")
mpfl.append(mpf)
pb = my_rectangle = round_rectangle(
11, 10, 11+300, 10+168,
fill = "#212121",
radius = radius,
outline = "")
ebt = canvas.create_text(
326, 43,
text = "Video URL:",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(13.0) - 5))
ebl.append(ebt)
mptt = canvas.create_text(
348, 103,
text = "MP3",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
mptl.append(mptt)
mpft = canvas.create_text(
440, 103,
text = "MP4",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(14.0) - 5))
mpfl.append(mpft)
canvas.create_text(
320, 13,
text = "Youtube Video Downloader",
fill = "#a0a0a0",
anchor = "nw",
font = ("None", int(15.0) - 5))
entry0_img = PhotoImage(file = f"img_textBox0.png")
entry0_bg = canvas.create_image(
406.0, 70.5,
image = entry0_img)
ebf = Entry(
bd = 0,
bg = "#212121",
fg = "#727272",
insertbackground = "#727272",
highlightthickness = 0)
ebf.place(
x = 326, y = 61,
width = 160,
height = 17)
def OnHover(item):
if item in mptl or mpfl:
if canvas.itemcget(item, "outline") == "":
if canvas.itemcget(item, "tag") == "clickset":
pass
else:
canvas.itemconfig(item, outline="#FF7276", width = olw, tag="hoverset")
else:
pass
def UnHover(item):
if item in mptl or mpfl:
if canvas.itemcget(item, "tag") == "hoverset":
canvas.itemconfig(item, outline="", width = olw, tag="")
else:
pass
def bindhover(l, item):
for i in l:
canvas.tag_bind(i, '<Enter>', lambda event: OnHover(item=item))
canvas.tag_bind(i, '<Leave>', lambda event: UnHover(item=item))
bindhover(mptl, mpt)
bindhover(mpfl, mpf)
bindhover(dl, d)
def OnClick(item):
global ft
if item in mptl or mpfl:
if canvas.itemcget(item, "tag") == "hoverset":
if item == mpt:
if canvas.itemcget(mpf, "outline") == "":
ft = "mp3"
else:
canvas.itemconfig(mpf, outline="")
ft = "mp3"
if item == mpf:
if canvas.itemcget(mpt, "outline") == "":
ft = "mp4"
else:
canvas.itemconfig(mpt, outline="")
ft = "mp4"
canvas.itemconfig(item, tag="clickset")
else:
pass
def bindclick(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: OnClick(item=item))
bindclick(mptl, mpt)
bindclick(mpfl, mpf)
def download():
e = False
link = ebf.get()
try:
link2 = YouTube(link)
except:
messagebox.showinfo("Invalid link", "Invalid youtube link")
e = True
if e == False:
if ft == None:
messagebox.showinfo("Select a file type", "No file type has been selected")
e = True
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
vid = video.download('Downloads')
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
else:
if e == False:
video = link2.streams.first()
vid = video.download('Downloads')
else:
pass
def bdownload(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: download())
bdownload(dl, d)
window.resizable(False, False)
window.mainloop()
下载:
def download():
e = False
link = ebf.get()
try:
link2 = YouTube(link)
except:
messagebox.showinfo("Invalid link", "Invalid youtube link")
e = True
if e == False:
if ft == None:
messagebox.showinfo("Select a file type", "No file type has been selected")
e = True
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
vid = video.download('Downloads')
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
else:
if e == False:
video = link2.streams.first()
vid = video.download('Downloads')
else:
pass
def bdownload(l, item):
for i in l:
canvas.tag_bind(i, '<Button-1>', lambda event: download())
bdownload(dl, d)
只是想知道如何将其放入线程中?
开始新话题的格式为:
new_thread = threading.Thread(target=..., daemon=True, args=(..., ...))
new_thread.start()
所以试试这个:
def download_worker(player, ft):
vid = video.download('Downloads')
if ft == "mp3":
print("test")
base, ext = os.path.splitext(vid)
new_file = base + '.mp3'
os.rename(vid, new_file)
def download():
...
elif ft == 'mp3':
if e == False:
video = link2.streams.filter(only_audio=True).first()
# Imagine this like: download_worker(video, ft)
new_thread = threading.Thread(target=download_worker, daemon=True, args=(video, ft))
new_thread.start()
else:
if e == False:
video = link2.streams.first()
# Imagine this like: download_worker(video, ft)
new_thread = threading.Thread(target=download_worker, daemon=True, args=(video, ft))
new_thread.start()
# Keep in mind that the `vid` variable doesn't exist here.
在这种情况下,目标函数是 download_worker
,参数是:video
和 ft
。
线程在目标函数结束时自动结束。