Я сделал небольшой проект, используя CustomTkinter и Pytube, для загрузки видео с YouTube с помощью простого графического интерфейса.
Программа не имеет ошибок при запуске в виде файла .py в IDE и Windows, если я дважды щелкаю мышью или использую терминал.
Затем я приступил к использованию auto-py-to-exe для преобразования файла в файл .exe. Я следовал инструкциям на веб-сайте CustomTkinter, и, хотя у меня были некоторые проблемы, мне удалось пройти этот процесс.
Однако окончательный файл .exe запускается, но только на мгновение, прежде чем снова закрыться. Запустив .exe из терминала cmd, находящегося в каталоге файла, я смог получить сообщение об ошибке:
Traceback (most recent call last):
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 158, in <module>
File "PyInstaller\hooks\rthooks\pyi_rth_pkgres.py", line 36, in _pyi_rthook
File "PyInstaller\loader\pyimod02_importers.py", line 419, in exec_module
File "pkg_resources\__init__.py", line 77, in <module>
ModuleNotFoundError: No module named 'pkg_resources.extern'
[55288] Failed to execute script 'pyi_rth_pkgres' due to unhandled exception!
Я не смог найти решение этой проблемы и поэтому оказался здесь.
Знаете ли вы, что может быть причиной этой ошибки? или действительно ли это является причиной того, что программа не работает должным образом?
Полный код:
import tkinter
import customtkinter
#from pytubefix import YouTube
from tkinter import filedialog
from moviepy.editor import *
from pathvalidate import sanitize_filename
#from pytubefix import Playlist
#from pytubefix.cli import on_progress\
from pytube import *
app = customtkinter.CTk(fg_color = "black")
app.geometry("700x550")
app.title("YouTube Download")
app.after(201, lambda :app.iconbitmap("normally would show the path to the file but removed for privacy"))
font = customtkinter.CTkFont(family='Trade Gothic LT Bold Condensed No. 20', size=30)
font2 = customtkinter.CTkFont(family='Trade Gothic LT Bold Condensed No. 20', size=20)
menu = ''
currenttype = ''
def MainMenuGUI():
menu = 'main'
title.grid_forget()
finishLabel.grid_forget()
Vprogbar.grid_forget()
link.grid_forget()
download.grid_forget()
backbutton.grid_forget()
pPercent.grid_forget()
app.grid_rowconfigure(0, weight=1)
app.grid_rowconfigure(1, weight=1)
app.grid_rowconfigure(2, weight=1)
app.grid_columnconfigure(0, weight=1)
app.grid_columnconfigure(1, weight=1)
WhatLabel.grid(row=0, column=0, columnspan=2, padx=100, pady=50)
Videobutton.grid(row=1, column=1, sticky=customtkinter.W, padx=50)
AudioButton.grid(row=1, column=0, sticky=customtkinter.E, padx=50)
PVideobutton.grid(row=2, column=1, sticky=customtkinter.W, padx=50, pady=50)
PAudioButton.grid(row=2, column=0, sticky=customtkinter.E, padx=50, pady=50)
def mp4_to_mp3(mp4, mp3):
mp4_without_frames = AudioFileClip(mp4)
mp4_without_frames.write_audiofile(mp3)
mp4_without_frames.close() # function call mp4_to_mp3("my_mp4_path.mp4", "audio.mp3")
def DownloadGUI(dtype):
global menu
menu = dtype
global currenttype
currenttype = dtype
WhatLabel.grid_forget()
Videobutton.grid_forget()
AudioButton.grid_forget()
PVideobutton.grid_forget()
PAudioButton.grid_forget()
Vprogbar.grid_forget()
pPercent.grid_forget()
Pprogbar.grid_forget()
app.grid_rowconfigure(0, weight=100)
app.grid_rowconfigure(1, weight=10)
app.grid_rowconfigure(2, weight=1)
app.grid_rowconfigure(3, weight=100)
title.grid(row=0, column=0, columnspan=2, sticky=customtkinter.S)
link.grid(row=1, column=0, columnspan=2)
download.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
finishLabel.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N)
backbutton.grid(row=3, column=1, columnspan=1)
finishLabel.configure(text='')
if currenttype == "Video" or currenttype == "Audio":
title.configure(text = "Insert a YouTube link")
download.configure(command=lambda: startdownload(dtype=currenttype))
else:
title.configure(text = "Insert a playlist link")
download.configure(command=lambda: startdownloadP(dtype=currenttype))
link.delete(0, customtkinter.END)
def startdownload(dtype):
try:
ytlink = link.get()
ytobject = YouTube(ytlink, on_progress_callback=Vprog)
title.configure(text=ytobject.title)
finishLabel.configure(text = "")
global menu
menu = str(dtype) + 'Download'
path = tkinter.filedialog.askdirectory(initialdir = "/", mustexist=True, parent=app)
pPercent.grid(row=1, column=0, columnspan=2, sticky=customtkinter.S)
link.grid_forget()
download.grid_forget()
Vprogbar.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
if dtype == "Video":
video = ytobject.streams.get_highest_resolution()
video.download(output_path=str(path))
elif dtype == "Audio":
audio = ytobject.streams.get_audio_only()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + "1" + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path)+"/"+sanitize_filename(audio.title) + "1" + ".mp4"):
os.remove(str(path)+"/"+sanitize_filename(audio.title) + "1" + ".mp4")
else:
audio.download(output_path=str(path), filename=sanitize_filename(audio.title)+".mp4")
clip = AudioFileClip(str(path)+"/"+sanitize_filename(audio.title)+".mp4")
clip.write_audiofile(str(path)+"/"+sanitize_filename(audio.title)+".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path)+"/"+sanitize_filename(audio.title)+".mp4"):
os.remove(str(path)+"/"+sanitize_filename(audio.title)+".mp4")
finishLabel.configure(text = "downloaded", text_color = "white")
except:
finishLabel.configure(text = "Download has failed", text_color = "red")
title.configure(text = "Insert a YouTube link")
Vprogbar.grid_forget()
link.grid(row=1, column=0, columnspan=2)
def startdownloadP(dtype):
vcount = 0
vccount = 0
playlink = Playlist(link.get())
path = tkinter.filedialog.askdirectory(initialdir = "/", mustexist=True, parent=app)
pPercent.grid(row=1, column=0, columnspan=2, sticky=customtkinter.S)
ppPercent.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N, pady=20)
link.grid_forget()
download.grid_forget()
Vprogbar.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
Pprogbar.grid(row=3, column=0, columnspan=2, sticky=customtkinter.N, pady=10)
for _ in playlink.videos:
vcount += 1
Pprog(vcount, 0)
for vid in playlink.videos:
vccount += 1
Pprog(vcount, vccount)
vid.register_on_progress_callback(Vprog)
title.configure(text=vid.title)
global menu
menu = str(dtype) + 'Download'
if dtype == "VideoPlaylist":
video = vid.streams.get_highest_resolution()
video.download(output_path=str(path))
elif dtype == "AudioPlaylist":
audio = vid.streams.get_audio_only()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + "1" + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4"):
os.remove(str(path) + "/" + sanitize_filename(audio.title) + "1" + ".mp4")
else:
audio.download(output_path=str(path), filename=sanitize_filename(audio.title) + ".mp4")
clip = AudioFileClip(str(path) + "/" + sanitize_filename(audio.title) + ".mp4")
clip.write_audiofile(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"[:-4] + ".mp3")
clip.close()
if os.path.exists(str(path) + "/" + sanitize_filename(audio.title) + ".mp4"):
os.remove(str(path) + "/" + sanitize_filename(audio.title) + ".mp4")
pPercent.grid_forget()
ppPercent.grid_forget()
Vprogbar.grid_forget()
Pprogbar.grid_forget()
finishLabel.grid(row=2, column=0, columnspan=2, sticky=customtkinter.N)
finishLabel.configure(text = "All videos downloaded", text_color = "white")
def Vprog(stream, chunk, bytes_remaining):
total_size = stream.filesize
bytes_downloaded = total_size - bytes_remaining
percentage_complete = bytes_downloaded / total_size * 100
per = str(int(percentage_complete))
pPercent.configure(text=per + "%")
pPercent.update()
Vprogbar.set(float(percentage_complete / 100))
pPercent.update()
Vprogbar.update()
def Pprog(total, current):
percentage_done = current / total * 100
per = str(int(percentage_done))
ppPercent.configure(text=per + "%")
Pprogbar.set(float(percentage_done / 100))
Pprogbar.update()
def Back():
if 'Download' in menu:
DownloadGUI(menu[:-8])
else:
MainMenuGUI()
urlvar = tkinter.StringVar()
title = customtkinter.CTkLabel(app, text = "Insert a YouTube link", fg_color='White',corner_radius=10, padx=50, font=font)
link = customtkinter.CTkEntry(app, width=350, height=40, textvariable=urlvar)
finishLabel = customtkinter.CTkLabel(app, text = "", text_color = "white")
pPercent = customtkinter.CTkLabel(app, text = "0%", text_color = "white")
ppPercent = customtkinter.CTkLabel(app, text = "0%", text_color = "white")
Vprogbar = customtkinter.CTkProgressBar(app, width=400, progress_color = "red")
Pprogbar = customtkinter.CTkProgressBar(app, width=400, progress_color = "red")
download = customtkinter.CTkButton(app, text = "Download", command=lambda: startdownload(dtype=currenttype), fg_color = "#e8e6e6", text_color = "black", hover_color='#c0c0c0')
Vprogbar.set(0)
Pprogbar.set(0)
backbutton = customtkinter.CTkButton(app, text_color='black', text = "back", width=50, height=50, fg_color='#333333', hover_color='#c0c0c0', command=Back)
WhatLabel = customtkinter.CTkLabel(app, text = "What would you like to download?", fg_color='White',corner_radius=10, padx=50, font=font)
Videobutton = customtkinter.CTkButton(app, text='Video', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='Video'))
AudioButton = customtkinter.CTkButton(app, text='Audio', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='Audio'))
PVideobutton = customtkinter.CTkButton(app, text='Video Playlist', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='VideoPlaylist'))
PAudioButton = customtkinter.CTkButton(app, text='Audio Playlist', width=250, height=150, font=font2, fg_color='#b01214', hover_color='#590404', command=lambda: DownloadGUI(dtype='AudioPlaylist'))
#https://thewikihow.com/video_cPAlmXHMktA
#https://www.youtube.com/playlist?list=PLpi4n5vOXXFkJxTSD8VRuZ9phHmojXaP1
#https://thewikihow.com/video_Ga2PA-vEiFk
#https://thewikihow.com/video_QU8pe3dhz8s&list=PLpi4n5vOXXFkJxTSD8VRuZ9phHmojXaP1&index=10
MainMenuGUI()
app.mainloop()
Я не знаю, что делать, потому что, честно говоря, у меня не так много знаний о том, что происходит в фоновом режиме библиотек, которые я использую, и поиск в Google проблемы, похоже, не дает ответов.






Согласно этому сообщению в блоге, исправить это должно быть легко. Это либо это:
ModuleNotFoundError: нет модуля с именем x / ImportError: нет модуля с именем x
Это означает, что конкретный модуль (в данном случае «x») не был добавлен в пакет. Я видел, как это происходило с пакетами в библиотеке pandas и win32api; если вы можете идентифицировать пакет (например, «x»), его очень легко исправить.
Чтобы исправить это в пользовательском интерфейсе, откройте вкладку «Дополнительно» и найдите входные данные --hidden-import. Просто вставьте имя модуля в это поле ввода, а затем переупакуйте. Если исходная ошибка все еще появляется, вы сделали это неправильно.
Например, если вам не хватает pandas._libs.tslib, добавьте «pandas._libs.tslib» во входные данные с помощью --hidden-import. Дополнительно вы можете добавить более одного модуля, например pandas._libs.tslib, win32api. (Для получения дополнительной информации см. знак вопроса рядом с входными данными).
Или это:
Альтернативно вы можете установить auto-py-to-exe в одной среде Python (одна установка или venv) и установить зависимый пакет в другой среде Python. Ознакомьтесь с «Как управлять несколькими дистрибутивами Python», чтобы узнать, делали ли вы это.
Спасибо, это мне помогло. поскольку я сделал это в Pycharm, у меня уже была папка Venv с Python и все, что было установлено. все, что мне нужно было сделать, это запустить auto-py-to-exe оттуда, и вуаля, все заработало! Единственная проблема заключается в том, что пока графический интерфейс остается открытым и работает нормально, загрузка не происходит. Думаю, в следующий раз я это исправлю :/