Okay it so when say you are doing 4 folders when one finishes don't wait for others start next one also so that is 4 always going and also add the same thing for videos so that it does multiple at a time exactly like the folder way and also add a drop down menu to select -f jpg but labeled it JPG and also -f png but label it PNG and also make it have the guis to be Egyptian space ascension theme and also optimize code and speed as much as possible here is code import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import os
import subprocess
import threading
import concurrent.futures
import queue
import sys

def select_input_folders():
    while True:
        folder = filedialog.askdirectory(title="Select Input Folder (Cancel to finish)")
        if folder:
            if folder not in input_folders:
                input_folders.append(folder)
                input_listbox.insert(tk.END, folder)
            else:
                messagebox.showwarning("Duplicate Folder", f"The folder '{folder}' is already selected.")
        else:
            break

def remove_selected_folders():
    selected_indices = list(input_listbox.curselection())
    selected_indices.reverse()  # Remove from the end to avoid index shifting
    for index in selected_indices:
        folder = input_listbox.get(index)
        input_folders.remove(folder)
        input_listbox.delete(index)

def select_output_folder():
    folder = filedialog.askdirectory(title="Select Output Folder")
    if folder:
        output_folder_var.set(folder)
        output_entry.config(state='normal')
        output_entry.delete(0, tk.END)
        output_entry.insert(0, folder)
        output_entry.config(state='readonly')

def sanitize_folder_name(name):
    """Sanitize the folder name to remove or replace problematic characters."""
    return "".join(c if c.isalnum() or c in (' ', '_', '-') else "_" for c in name).replace(" ", "_")

def process_videos_thread():
    """Run the video processing in a separate thread."""
    threading.Thread(target=process_videos, daemon=True).start()

def process_videos():
    output_folder = output_folder_var.get()

    if not input_folders:
        messagebox.showerror("Error", "Please select at least one input folder.")
        return
    if not output_folder:
        messagebox.showerror("Error", "Please select an output folder.")
        return

    # Ensure the output directory exists
    os.makedirs(output_folder, exist_ok=True)

    # Disable the process button and folder selection buttons to prevent multiple clicks
    set_buttons_state(tk.DISABLED)

    # Initialize progress bar
    progress_bar.config(maximum=len(input_folders))
    progress_bar['value'] = 0
    status_label.config(text="Starting processing...")

    # Queue to receive progress updates
    progress_queue = queue.Queue()

    # List to collect errors
    errors = []

    def worker(folder):
        base_name = os.path.basename(os.path.normpath(folder))
        sanitized_base = sanitize_folder_name(base_name)
        unique_output_dir = os.path.join(output_folder, f"{sanitized_base}_{base_name}")
        os.makedirs(unique_output_dir, exist_ok=True)
        try:
            # Run the video2image command with the unique output directory
            subprocess.run(
                ['video2image', '-i', folder, '-o', unique_output_dir, '-f', 'jpg'],
                check=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            progress_queue.put(("success", folder))
        except subprocess.CalledProcessError as e:
            error_msg = f"Failed to process folder: {folder}\nError: {e.stderr.decode().strip()}"
            progress_queue.put(("error", error_msg))
        except Exception as ex:
            error_msg = f"An unexpected error occurred while processing folder: {folder}\nError: {ex}"
            progress_queue.put(("error", error_msg))

    # Determine the number of workers based on CPU count
    max_workers = min(4, os.cpu_count() or 1)  # Adjust this number as needed
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)

    # Submit all tasks
    futures = [executor.submit(worker, folder) for folder in input_folders]

    # Function to periodically check the queue
    def check_queue():
        try:
            while True:
                status, info = progress_queue.get_nowait()
                if status == "success":
                    progress_bar['value'] += 1
                    status_label.config(text=f"Processed: {info}")
                elif status == "error":
                    errors.append(info)
                    progress_bar['value'] += 1
                    status_label.config(text=f"Error: {info}")

                if progress_bar['value'] >= len(input_folders):
                    executor.shutdown(wait=False)
                    finalize_processing()
        except queue.Empty:
            pass
        if progress_bar['value'] < len(input_folders):
            root.after(100, check_queue)

    # Start checking the queue
    root.after(100, check_queue)

    def finalize_processing():
        set_buttons_state(tk.NORMAL)
        if errors:
            error_message = "\n\n".join(errors)
            messagebox.showerror("Processing Completed with Errors", error_message)
        else:
            messagebox.showinfo("Success", "All videos have been successfully processed.")
        progress_bar['value'] = 0
        status_label.config(text="Processing completed.")

def set_buttons_state(state):
    process_button.config(state=state)
    select_input_button.config(state=state)
    select_output_button.config(state=state)
    remove_button.config(state=state if input_folders else tk.DISABLED)

# Initialize the main window
root = tk.Tk()
root.title("Video to Image Converter")
root.geometry("800x600")
root.resizable(True, True)  # Allow resizing for better usability

# Initialize the list to store input folders
input_folders = []

# Variable to store output folder path
output_folder_var = tk.StringVar()

# Style configuration
style = ttk.Style(root)
style.theme_use('clam')  # You can choose another theme like 'default', 'alt', 'classic', etc.
style.configure("TButton", padding=6)
style.configure("TLabelFrame", padding=10)
style.configure("Horizontal.TProgressbar", troughcolor='white', bordercolor='black',
                background='green', lightcolor='green', darkcolor='green')

# Frame for Input Folders
input_frame = ttk.LabelFrame(root, text="Input Folders")
input_frame.pack(fill="both", expand=True, padx=20, pady=10)

# Listbox to display selected input folders
input_listbox = tk.Listbox(input_frame, selectmode=tk.MULTIPLE, height=15)
input_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0,5), pady=5)

# Scrollbar for the listbox
input_scroll = ttk.Scrollbar(input_frame, orient=tk.VERTICAL, command=input_listbox.yview)
input_scroll.pack(side=tk.RIGHT, fill=tk.Y)
input_listbox.config(yscrollcommand=input_scroll.set)

# Frame for Input Buttons
input_button_frame = ttk.Frame(root)
input_button_frame.pack(fill='x', padx=20, pady=(0,10))

# Button to select input folders
select_input_button = ttk.Button(input_button_frame, text="Select Input Folders", command=select_input_folders)
select_input_button.pack(side=tk.LEFT, padx=5)

# Button to remove selected input folders
remove_button = ttk.Button(input_button_frame, text="Remove Selected", command=remove_selected_folders, state=tk.DISABLED)
remove_button.pack(side=tk.LEFT, padx=5)

# Frame for Output Folder
output_frame = ttk.LabelFrame(root, text="Output Folder")
output_frame.pack(fill="both", expand=True, padx=20, pady=10)

# Entry widget to display selected output folder
output_entry = ttk.Entry(output_frame, textvariable=output_folder_var, width=80, state='readonly')
output_entry.pack(side=tk.LEFT, padx=(0, 5), expand=True, fill=tk.X)

# Button to select output folder
select_output_button = ttk.Button(output_frame, text="Select Output Folder", command=select_output_folder)
select_output_button.pack(side=tk.LEFT, padx=5)

# Progress Frame
progress_frame = ttk.Frame(root)
progress_frame.pack(fill='x', padx=20, pady=10)

progress_label = ttk.Label(progress_frame, text="Processing Progress:")
progress_label.pack(anchor='w')

progress_bar = ttk.Progressbar(progress_frame, orient='horizontal', length=760,
                               mode='determinate', style="Horizontal.TProgressbar")
progress_bar.pack(pady=5, fill='x')

# Status Label
status_label = ttk.Label(root, text="Ready.", relief='sunken', anchor='w')
status_label.pack(fill='x', padx=20, pady=(0,10))

# Process Button
process_button = ttk.Button(root, text="Process Videos", command=process_videos_thread)
process_button.pack(pady=10, ipadx=10, ipady=5)

def on_input_folders_change(*args):
    """Enable or disable the remove button based on folder selection."""
    if input_folders:
        remove_button.config(state=tk.NORMAL)
    else:
        remove_button.config(state=tk.DISABLED)

# Monitor changes in the input_folders list to update the remove button state
def monitor_input_folders():
    """Periodically check if input_folders is empty to enable/disable the remove button."""
    on_input_folders_change()
    root.after(500, monitor_input_folders)

monitor_input_folders()

# Run the GUI loop
root.mainloop()