Speed this up with choco copy import os
import shutil
from tkinter import (
    Tk,
    Button,
    Label,
    Listbox,
    END,
    MULTIPLE,
    filedialog,
    messagebox,
    StringVar,
)
from tkinter.ttk import Progressbar

class ImageCombinerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Image Sequence Combiner")

        self.source_folders = []
        self.destination_folder = ""

        # Source Folders Selection
        self.btn_select_sources = Button(
            root, text="Select Source Folders", command=self.select_source_folders
        )
        self.btn_select_sources.pack(pady=5)

        self.lbl_sources = Label(root, text="No source folders selected.")
        self.lbl_sources.pack()

        # Destination Folder Selection
        self.btn_select_destination = Button(
            root, text="Select Destination Folder", command=self.select_destination_folder
        )
        self.btn_select_destination.pack(pady=5)

        self.lbl_destination = Label(root, text="No destination folder selected.")
        self.lbl_destination.pack()

        # Start Button
        self.btn_start = Button(
            root, text="Combine Images", command=self.combine_images
        )
        self.btn_start.pack(pady=20)

        # Progress Bar
        self.progress = Progressbar(root, orient="horizontal", length=400, mode="determinate")
        self.progress.pack(pady=10)

    def select_source_folders(self):
        while True:
            folder = filedialog.askdirectory(mustexist=True, title="Select a Source Folder")
            if folder:
                if folder not in self.source_folders:
                    self.source_folders.append(folder)
                    self.lbl_sources.config(text=f"Selected {len(self.source_folders)} source folder(s).")
                else:
                    messagebox.showinfo("Duplicate Folder", "This folder has already been selected.")
                # Ask if the user wants to select another folder
                another = messagebox.askyesno("Select Another", "Do you want to select another source folder?")
                if not another:
                    break
            else:
                break

    def select_destination_folder(self):
        folder = filedialog.askdirectory(mustexist=True, title="Select Destination Folder")
        if folder:
            self.destination_folder = folder
            self.lbl_destination.config(text=f"Destination: {self.destination_folder}")

    def combine_images(self):
        if not self.source_folders:
            messagebox.showwarning("No Source Folders", "Please select source folders first.")
            return
        if not self.destination_folder:
            messagebox.showwarning("No Destination Folder", "Please select a destination folder.")
            return

        total_files = 0
        file_operations = []

        # Gather all image files with their new prefixed names
        for src_folder in self.source_folders:
            main_prefix = os.path.basename(src_folder)
            for subdir, _, files in os.walk(src_folder):
                sub_prefix = os.path.basename(subdir)
                for file in files:
                    if self.is_image_file(file):
                        total_files += 1
                        new_prefix = f"{main_prefix}_{sub_prefix}"
                        new_filename = f"{new_prefix}_{file}"
                        src_file = os.path.join(subdir, file)
                        dest_file = os.path.join(self.destination_folder, new_filename)
                        file_operations.append((src_file, dest_file))

        if total_files == 0:
            messagebox.showinfo("No Images Found", "No image files were found in the selected source folders.")
            return

        # Initialize progress bar
        self.progress["maximum"] = total_files
        self.progress["value"] = 0

        # Copy files
        for idx, (src, dest) in enumerate(file_operations, start=1):
            try:
                shutil.copy2(src, dest)  # copy2 preserves metadata
            except Exception as e:
                messagebox.showerror("Error", f"Failed to copy {src} to {dest}.\n\nError: {e}")
                return
            self.progress["value"] = idx
            self.root.update_idletasks()

        messagebox.showinfo("Success", f"Successfully combined {total_files} images into {self.destination_folder}.")

    @staticmethod
    def is_image_file(filename):
        image_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff', '.webp')
        return filename.lower().endswith(image_extensions)

def main():
    root = Tk()
    app = ImageCombinerGUI(root)
    root.geometry("450x300")
    root.resizable(False, False)
    root.mainloop()

if __name__ == "__main__":
    main()