Input folder selection is not working and it should be adding folders I select and also allow multiple folders 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():
    selected_folders = input_folders_var.get()
    while True:
        folder = filedialog.askdirectory(title="Select Input Folder (Cancel to finish)")
        if folder:
            if folder not in selected_folders:
                selected_folders.append(folder)
                input_text.insert(tk.END, folder + "\n")
            else:
                messagebox.showwarning("Duplicate Folder", f"The folder '{folder}' is already selected.")
        else:
            break
    input_folders_var.set(selected_folders)

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():
    input_folders = input_folders_var.get()
    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)

# Initialize the main window
root = tk.Tk()
root.title("Video to Image Converter")
root.geometry("800x600")
root.resizable(False, False)

# Variables to store folder paths
input_folders_var = tk.Variable(value=[])
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)

# Text widget to display selected input folders
input_text = tk.Text(input_frame, height=15, width=100, wrap=tk.WORD, state='normal', bd=2, relief='sunken')
input_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0,5), pady=5)

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

# Button to select input folders
select_input_button = ttk.Button(root, text="Select Input Folders", command=select_input_folders)
select_input_button.pack(pady=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=100, 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)

# 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)

# Run the GUI loop
root.mainloop()