From aef43bd2f8909c0a0aa36efc4a06834ca7ad4658 Mon Sep 17 00:00:00 2001 From: solidlime Date: Wed, 7 Jan 2026 20:59:15 +0900 Subject: [PATCH] Refactor: Simplify file picker and auto-extract folder path Major changes: - Changed input parameter from 'path' to 'image' for clarity - Auto-extract folder path from file selection in folder mode - Simplified JavaScript widget implementation - Added OUTPUT_IS_LIST flag for proper output handling - Improved file selection UI with emoji icons - Added helpful info widget explaining the modes Features: - Single mode: Load selected file directly - Folder mode: Extract folder from selected file, then pick random image - Better user feedback with console logging - More robust path handling (file or directory input) --- random_image_picker.py | 36 +++++++------ web/random_image_picker.js | 100 +++++++++++++++++-------------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/random_image_picker.py b/random_image_picker.py index a78d5cb..f64115f 100644 --- a/random_image_picker.py +++ b/random_image_picker.py @@ -28,10 +28,9 @@ class RandomImagePicker: return { "required": { - "path": ("STRING", { + "image": ("STRING", { "default": default_path, "multiline": False, - "placeholder": "Path to image file or folder" }), "folder_mode": ("BOOLEAN", { "default": False, @@ -56,6 +55,7 @@ class RandomImagePicker: FUNCTION = "load_image" CATEGORY = "image" OUTPUT_NODE = True + OUTPUT_IS_LIST = (False, False, False) @staticmethod def get_image_files(directory: str, include_subfolders: bool = False) -> List[str]: @@ -114,12 +114,12 @@ class RandomImagePicker: return img_tensor, width, height - def load_image(self, path: str, folder_mode: bool, include_subfolders: bool, seed: int): + def load_image(self, image: str, folder_mode: bool, include_subfolders: bool, seed: int): """ Load image based on mode settings. Args: - path: File or folder path + image: File path (single mode) or file path to extract folder from (folder mode) folder_mode: True for folder mode, False for single file mode include_subfolders: Whether to scan subfolders seed: Random seed for folder mode @@ -127,31 +127,39 @@ class RandomImagePicker: Returns: Tuple of (image_tensor, width, height) """ - if not path or not os.path.exists(path): - raise ValueError(f"Path does not exist: {path}") + if not image or not os.path.exists(image): + raise ValueError(f"Path does not exist: {image}") if folder_mode: - # Folder mode: pick random image - if not os.path.isdir(path): - raise ValueError(f"Folder mode enabled but path is not a directory: {path}") + # Folder mode: extract folder from file path and pick random image + if os.path.isfile(image): + # Extract folder path from file path + folder_path = os.path.dirname(image) + elif os.path.isdir(image): + # Direct folder path + folder_path = image + else: + raise ValueError(f"Invalid path: {image}") - image_files = self.get_image_files(path, include_subfolders) + image_files = self.get_image_files(folder_path, include_subfolders) if not image_files: - raise ValueError(f"No image files found in directory: {path}") + raise ValueError(f"No image files found in directory: {folder_path}") # Use seed for reproducible random selection random.seed(seed) selected_image = random.choice(image_files) + print(f"[Random Image Picker] Folder: {folder_path}") print(f"[Random Image Picker] Selected: {selected_image}") return self.load_image_file(selected_image) else: # Single file mode - if not os.path.isfile(path): - raise ValueError(f"Single file mode enabled but path is not a file: {path}") + if not os.path.isfile(image): + raise ValueError(f"Single file mode enabled but path is not a file: {image}") - return self.load_image_file(path) + print(f"[Random Image Picker] Loading: {image}") + return self.load_image_file(image) # Node registration diff --git a/web/random_image_picker.js b/web/random_image_picker.js index b7dddd2..4214992 100644 --- a/web/random_image_picker.js +++ b/web/random_image_picker.js @@ -1,4 +1,5 @@ import { app } from "../../scripts/app.js"; +import { ComfyWidgets } from "../../scripts/widgets.js"; app.registerExtension({ name: "Comfy.RandomImagePicker", @@ -8,63 +9,54 @@ app.registerExtension({ const onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = function () { - const result = onNodeCreated?.apply(this, arguments); + const ret = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined; - // Add file browser button - const pathWidget = this.widgets.find(w => w.name === "path"); - if (pathWidget) { - // Add button to open file dialog - const button = this.addWidget("button", "Browse...", null, () => { - // Create file input element - const input = document.createElement("input"); - - // Get folder_mode widget value - const folderModeWidget = this.widgets.find(w => w.name === "folder_mode"); - const isFolderMode = folderModeWidget?.value || false; - - if (isFolderMode) { - // Folder selection - input.type = "file"; - input.webkitdirectory = true; - input.directory = true; - } else { - // File selection - input.type = "file"; - input.accept = "image/png, image/jpeg, image/webp, image/bmp, image/gif"; - } - - input.onchange = (e) => { - if (e.target.files && e.target.files[0]) { - if (isFolderMode) { - // Get folder path from first file - const firstFile = e.target.files[0]; - const fullPath = firstFile.webkitRelativePath || firstFile.name; - const folderPath = fullPath.split('/')[0]; - pathWidget.value = folderPath; - } else { - // Get file path - const file = e.target.files[0]; - // Note: For security reasons, browsers don't expose full file paths - // We can only get the file name, not the full path - // Users will need to manually enter the full path or use relative paths - pathWidget.value = file.name; - - // Show info message - console.log("Note: Due to browser security, full path is not available. Please enter the complete path manually."); - } - } - }; - - input.click(); - }); + // Find the image widget + const imageWidget = this.widgets.find(w => w.name === "image"); + if (!imageWidget) return ret; + + // Create file input button widget + const fileWidget = this.addWidget("button", "📁 Choose File", "file", () => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = "image/png,image/jpeg,image/jpg,image/webp,image/bmp,image/gif"; - // Add helper text - this.addWidget("text", "helper", "Tip: Enter full path or use ComfyUI input folder", () => {}, { - serialize: false - }); - } + input.onchange = (e) => { + if (e.target.files && e.target.files[0]) { + const file = e.target.files[0]; + + // Create a URL for the file + const reader = new FileReader(); + reader.onload = (event) => { + // Get file path (name only, browser security limitation) + const fileName = file.name; + + // Try to use the webkitRelativePath or fall back to name + const filePath = file.webkitRelativePath || file.path || fileName; + + // Update the image widget value + imageWidget.value = filePath; + + console.log("Selected file:", filePath); + + // Show notification + app.ui.dialog.show(`File selected: ${fileName}\n\nNote: You may need to enter the full path manually due to browser security restrictions.`); + }; + reader.readAsDataURL(file); + } + }; + + input.click(); + }); - return result; + // Add info widget + const infoWidget = this.addWidget("text", "â„šī¸ Info", + "Single mode: Select any image file\nFolder mode: File's folder will be used", + () => {}, + { serialize: false } + ); + + return ret; }; } }