mirror of
https://github.com/Anjok07/ultimatevocalremovergui.git
synced 2024-11-28 01:10:56 +01:00
Added Drag & Drop & Bug fixes
- Added Drag & Drop for the save to directory and the music file selection (#2) - Fixed Model Names not decoding correctly
This commit is contained in:
parent
3a16689c8e
commit
db5c323003
166
VocalRemover.py
166
VocalRemover.py
@ -4,6 +4,7 @@ import tkinter.ttk as ttk
|
||||
import tkinter.messagebox
|
||||
import tkinter.filedialog
|
||||
import tkinter.font
|
||||
from tkinterdnd2 import TkinterDnD, DND_FILES # Enable Drag & Drop
|
||||
from datetime import datetime
|
||||
# Images
|
||||
from PIL import Image
|
||||
@ -168,6 +169,30 @@ def get_model_values(model_name):
|
||||
return model_values
|
||||
|
||||
|
||||
def drop(var, event, accept_mode: str = 'files'):
|
||||
"""
|
||||
Drag & Drop verification process
|
||||
"""
|
||||
path = event.data
|
||||
|
||||
if accept_mode == 'folder':
|
||||
path = path.replace('{', '').replace('}', '')
|
||||
if not os.path.isdir(path):
|
||||
tk.messagebox.showerror(title='Invalid Folder',
|
||||
message='Your given export path is not a valid folder!')
|
||||
return
|
||||
elif accept_mode == 'files':
|
||||
# Clean path text and set path to the list of paths
|
||||
path = path[:-1]
|
||||
path = path.replace('{', '')
|
||||
path = path.split('} ')
|
||||
else:
|
||||
# Invalid accept mode
|
||||
return
|
||||
|
||||
var.set(path)
|
||||
|
||||
|
||||
class ThreadSafeConsole(tk.Text):
|
||||
"""
|
||||
Text Widget which is thread safe for tkinter
|
||||
@ -201,7 +226,7 @@ class ThreadSafeConsole(tk.Text):
|
||||
self.after(100, self.update_me)
|
||||
|
||||
|
||||
class MainWindow(tk.Tk):
|
||||
class MainWindow(TkinterDnD.Tk):
|
||||
# --Constants--
|
||||
# Layout
|
||||
IMAGE_HEIGHT = 140
|
||||
@ -233,6 +258,7 @@ class MainWindow(tk.Tk):
|
||||
xpad=int(self.winfo_screenwidth()/2 - 550/2),
|
||||
ypad=int(self.winfo_screenheight()/2 - height/2 - 30)))
|
||||
self.configure(bg='#000000') # Set background color to black
|
||||
self.protocol("WM_DELETE_WINDOW", self.save_values)
|
||||
self.resizable(False, False)
|
||||
self.update()
|
||||
|
||||
@ -249,7 +275,7 @@ class MainWindow(tk.Tk):
|
||||
data = load_data()
|
||||
# Paths
|
||||
self.exportPath_var = tk.StringVar(value=data['export_path'])
|
||||
self.inputPaths = []
|
||||
self.inputPaths_var = tk.StringVar(value='')
|
||||
# Processing Options
|
||||
self.gpuConversion_var = tk.BooleanVar(value=data['gpu'])
|
||||
self.postprocessing_var = tk.BooleanVar(value=data['postprocess'])
|
||||
@ -280,6 +306,7 @@ class MainWindow(tk.Tk):
|
||||
# --Widgets--
|
||||
self.create_widgets()
|
||||
self.configure_widgets()
|
||||
self.bind_widgets()
|
||||
self.place_widgets()
|
||||
|
||||
self.update_available_models()
|
||||
@ -321,6 +348,21 @@ class MainWindow(tk.Tk):
|
||||
font=self.font, foreground='white')
|
||||
ttk.Style().configure('T', font=self.font, foreground='white')
|
||||
|
||||
def bind_widgets(self):
|
||||
"""Bind widgets to the drag & drop mechanic"""
|
||||
self.filePaths_saveTo_Button.drop_target_register(DND_FILES)
|
||||
self.filePaths_saveTo_Entry.drop_target_register(DND_FILES)
|
||||
self.filePaths_musicFile_Button.drop_target_register(DND_FILES)
|
||||
self.filePaths_musicFile_Entry.drop_target_register(DND_FILES)
|
||||
self.filePaths_saveTo_Button.dnd_bind('<<Drop>>',
|
||||
lambda e, var=self.exportPath_var: drop(var, e, accept_mode='folder'))
|
||||
self.filePaths_saveTo_Entry.dnd_bind('<<Drop>>',
|
||||
lambda e, var=self.exportPath_var: drop(var, e, accept_mode='folder'))
|
||||
self.filePaths_musicFile_Button.dnd_bind('<<Drop>>',
|
||||
lambda e, var=self.inputPaths_var: drop(var, e, accept_mode='files'))
|
||||
self.filePaths_musicFile_Entry.dnd_bind('<<Drop>>',
|
||||
lambda e, var=self.inputPaths_var: drop(var, e, accept_mode='files'))
|
||||
|
||||
def place_widgets(self):
|
||||
"""Place main widgets"""
|
||||
self.title_Label.place(x=-2, y=-2)
|
||||
@ -354,7 +396,7 @@ class MainWindow(tk.Tk):
|
||||
text='Select Your Audio File(s)',
|
||||
command=self.open_file_filedialog)
|
||||
self.filePaths_musicFile_Entry = ttk.Entry(master=self.filePaths_Frame,
|
||||
text=self.inputPaths,
|
||||
textvariable=self.inputPaths_var,
|
||||
state=tk.DISABLED
|
||||
)
|
||||
# -Place Widgets-
|
||||
@ -557,13 +599,7 @@ class MainWindow(tk.Tk):
|
||||
initialdir=self.lastDir,
|
||||
)
|
||||
if paths: # Path selected
|
||||
self.inputPaths = paths
|
||||
# Change the entry text
|
||||
self.filePaths_musicFile_Entry.configure(state=tk.NORMAL)
|
||||
self.filePaths_musicFile_Entry.delete(0, tk.END)
|
||||
self.filePaths_musicFile_Entry.insert(0, self.inputPaths)
|
||||
self.filePaths_musicFile_Entry.configure(state=tk.DISABLED)
|
||||
|
||||
self.inputPaths_var.set(paths)
|
||||
self.lastDir = os.path.dirname(paths[0])
|
||||
|
||||
def open_export_filedialog(self):
|
||||
@ -584,6 +620,7 @@ class MainWindow(tk.Tk):
|
||||
"""
|
||||
# -Get all variables-
|
||||
export_path = self.exportPath_var.get()
|
||||
input_paths = self.inputPaths_var.get()
|
||||
instrumentalModel_path = self.instrumentalLabel_to_path[self.instrumentalModel_var.get()] # nopep8
|
||||
stackedModel_path = self.stackedLabel_to_path[self.stackedModel_var.get()] # nopep8
|
||||
# Get constants
|
||||
@ -613,12 +650,13 @@ class MainWindow(tk.Tk):
|
||||
return
|
||||
|
||||
# -Check for invalid inputs-
|
||||
if not any([(os.path.isfile(path) and path.endswith(('.mp3', '.mp4', '.m4a', '.flac', '.wav')))
|
||||
for path in self.inputPaths]):
|
||||
tk.messagebox.showwarning(master=self,
|
||||
title='Invalid Music File',
|
||||
message='You have selected an invalid music file!\nPlease make sure that your files still exist and ends with either ".mp3", ".mp4", ".m4a", ".flac", ".wav"')
|
||||
return
|
||||
for path in input_paths:
|
||||
if not os.path.isfile(path):
|
||||
tk.messagebox.showwarning(master=self,
|
||||
title='Invalid Music File',
|
||||
message='You have selected an invalid music file! Please make sure that the file still exists!',
|
||||
detail=f'File path: {path}')
|
||||
return
|
||||
if not os.path.isdir(export_path):
|
||||
tk.messagebox.showwarning(master=self,
|
||||
title='Invalid Export Directory',
|
||||
@ -638,27 +676,6 @@ class MainWindow(tk.Tk):
|
||||
message='You have selected an invalid stacked model file!\nPlease make sure that your model file still exists!')
|
||||
return
|
||||
|
||||
# -Save Data-
|
||||
save_data(data={
|
||||
'export_path': export_path,
|
||||
'gpu': self.gpuConversion_var.get(),
|
||||
'postprocess': self.postprocessing_var.get(),
|
||||
'tta': self.tta_var.get(),
|
||||
'output_image': self.outputImage_var.get(),
|
||||
'stack': self.stack_var.get(),
|
||||
'stackOnly': self.stackOnly_var.get(),
|
||||
'stackPasses': stackPasses,
|
||||
'saveAllStacked': self.saveAllStacked_var.get(),
|
||||
'sr': sr,
|
||||
'hop_length': hop_length,
|
||||
'window_size': window_size,
|
||||
'n_fft': n_fft,
|
||||
'useModel': 'instrumental', # Always instrumental
|
||||
'lastDir': self.lastDir,
|
||||
'modelFolder': self.modelFolder_var.get(),
|
||||
'aiModel': self.aiModel_var.get(),
|
||||
})
|
||||
|
||||
if self.aiModel_var.get() == 'v2':
|
||||
inference = inference_v2
|
||||
elif self.aiModel_var.get() == 'v4':
|
||||
@ -670,7 +687,7 @@ class MainWindow(tk.Tk):
|
||||
threading.Thread(target=inference.main,
|
||||
kwargs={
|
||||
# Paths
|
||||
'input_paths': self.inputPaths,
|
||||
'input_paths': input_paths,
|
||||
'export_path': export_path,
|
||||
# Processing Options
|
||||
'gpu': 0 if self.gpuConversion_var.get() else -1,
|
||||
@ -726,20 +743,19 @@ class MainWindow(tk.Tk):
|
||||
# Loop through each constant (key) and its widgets
|
||||
for key, (widget, var) in widgetsVars.items():
|
||||
if stacked_selectable:
|
||||
# Stacked model can be selected
|
||||
if key in stacked.keys():
|
||||
if (key in stacked.keys() and
|
||||
not instrumental_selectable):
|
||||
# Only stacked selectable
|
||||
widget.configure(state=tk.DISABLED)
|
||||
var.set(stacked[key])
|
||||
continue
|
||||
elif (key in instrumental.keys() and
|
||||
instrumental_selectable):
|
||||
if instrumental_selectable:
|
||||
if (key in instrumental.keys() and
|
||||
key in stacked.keys()):
|
||||
# Both models have set constants
|
||||
widget.configure(state=tk.DISABLED)
|
||||
var.set('%d/%d' % (instrumental[key], stacked[key]))
|
||||
continue
|
||||
else:
|
||||
if key in stacked.keys():
|
||||
# Only stacked selectable
|
||||
widget.configure(state=tk.DISABLED)
|
||||
var.set(stacked[key])
|
||||
continue
|
||||
else:
|
||||
# Stacked model can not be selected
|
||||
if (key in instrumental.keys() and
|
||||
@ -837,7 +853,6 @@ class MainWindow(tk.Tk):
|
||||
# Instrumental Model
|
||||
self.options_instrumentalModel_Label.configure(foreground='#000')
|
||||
self.options_instrumentalModel_Optionmenu.configure(state=tk.NORMAL) # nopep8
|
||||
self.instrumentalModel_var.set('')
|
||||
|
||||
# Stack Model
|
||||
if stackLoops > 0:
|
||||
@ -885,11 +900,54 @@ class MainWindow(tk.Tk):
|
||||
"""
|
||||
Restart the application after asking for confirmation
|
||||
"""
|
||||
proceed = tk.messagebox.askyesno(title='Confirmation',
|
||||
message='The application will restart and lose unsaved data. Do you wish to proceed?')
|
||||
if proceed:
|
||||
subprocess.Popen(f'python "{__file__}"', shell=True)
|
||||
exit()
|
||||
save = tk.messagebox.askyesno(title='Confirmation',
|
||||
message='The application will restart. Do you want to save the data?')
|
||||
if save:
|
||||
self.save_values()
|
||||
subprocess.Popen(f'python "{__file__}"', shell=True)
|
||||
exit()
|
||||
|
||||
def save_values(self):
|
||||
"""
|
||||
Save the data of the application
|
||||
"""
|
||||
export_path = self.exportPath_var.get()
|
||||
# Get constants
|
||||
instrumental = get_model_values(self.instrumentalModel_var.get())
|
||||
stacked = get_model_values(self.stackedModel_var.get())
|
||||
if [bool(instrumental), bool(stacked)].count(True) == 2:
|
||||
sr = DEFAULT_DATA['sr']
|
||||
hop_length = DEFAULT_DATA['hop_length']
|
||||
window_size = DEFAULT_DATA['window_size']
|
||||
n_fft = DEFAULT_DATA['n_fft']
|
||||
else:
|
||||
sr = self.srValue_var.get()
|
||||
hop_length = self.hopValue_var.get()
|
||||
window_size = self.winSize_var.get()
|
||||
n_fft = self.nfft_var.get()
|
||||
|
||||
# -Save Data-
|
||||
save_data(data={
|
||||
'export_path': export_path,
|
||||
'gpu': self.gpuConversion_var.get(),
|
||||
'postprocess': self.postprocessing_var.get(),
|
||||
'tta': self.tta_var.get(),
|
||||
'output_image': self.outputImage_var.get(),
|
||||
'stack': self.stack_var.get(),
|
||||
'stackOnly': self.stackOnly_var.get(),
|
||||
'stackPasses': self.stackLoops_var.get(),
|
||||
'saveAllStacked': self.saveAllStacked_var.get(),
|
||||
'sr': sr,
|
||||
'hop_length': hop_length,
|
||||
'window_size': window_size,
|
||||
'n_fft': n_fft,
|
||||
'useModel': 'instrumental',
|
||||
'lastDir': self.lastDir,
|
||||
'modelFolder': self.modelFolder_var.get(),
|
||||
'aiModel': self.aiModel_var.get(),
|
||||
})
|
||||
|
||||
self.destroy()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user