diff --git a/IFLoadImagesNodeS.py b/IFLoadImagesNodeS.py index fb2385a..c6eb754 100644 --- a/IFLoadImagesNodeS.py +++ b/IFLoadImagesNodeS.py @@ -388,7 +388,6 @@ class IFLoadImagess: if f.startswith(ImageManager.THUMBNAIL_PREFIX)]) available_images = max(1, available_images) # Ensure at least 1 - # Get thumbnail files files = [f for f in os.listdir(input_dir) if f.startswith(ImageManager.THUMBNAIL_PREFIX)] @@ -397,7 +396,8 @@ class IFLoadImagess: "image": (sorted(files), {"image_upload": True}), "input_path": ("STRING", {"default": ""}), "start_index": ("INT", {"default": 0, "min": 0, "max": 9999}), - "max_images": ("INT", {"default": available_images, "min": 1, "max": available_images}), + "stop_index": ("INT", {"default": 10, "min": 1, "max": 9999}), # Changed to stop_index + "load_limit": (["10", "100", "1000", "10000", "100000"], {"default": "1000"}), "image_selected": ("BOOLEAN", {"default": False}), "available_image_count": ("INT", { "default": available_images, @@ -408,10 +408,6 @@ class IFLoadImagess: "include_subfolders": ("BOOLEAN", {"default": True}), "sort_method": (["alphabetical", "numerical", "date_created", "date_modified"],), "filter_type": (["none", "png", "jpg", "jpeg", "webp", "gif", "bmp"],), - }, - "hidden": { - "image_name": "IMAGE_NAME", - "unique_id": "UNIQUE_ID" } } @@ -445,14 +441,15 @@ class IFLoadImagess: logging.warning(f"Error in IS_CHANGED: {e}") return float("NaN") - def load_images(self, image="", input_path="", start_index=0, max_images=1, - image_selected=False, available_image_count=0, include_subfolders=True, - sort_method="numerical", filter_type="none", image_name="", unique_id=None): + def load_images(self, image="", input_path="", start_index=0, stop_index=10, + load_limit="1000", image_selected=False, available_image_count=0, + include_subfolders=True, sort_method="numerical", + filter_type="none", image_name="", unique_id=None): try: # Process input path abs_path = os.path.abspath(input_path if os.path.isabs(input_path) else os.path.join(folder_paths.get_input_directory(), input_path)) - + # Get all valid images first all_files = ImageManager.get_image_files(abs_path, include_subfolders, filter_type) if not all_files: @@ -462,39 +459,34 @@ class IFLoadImagess: # Sort files all_files = ImageManager.sort_files(all_files, sort_method) + total_files = len(all_files) + # Validate indices + start_index = min(max(0, start_index), total_files) + stop_index = min(max(start_index + 1, stop_index), total_files) + num_images = min(stop_index - start_index, int(load_limit)) + # Generate thumbnails success, _, all_thumbnails, image_order = ImageManager.create_thumbnails( abs_path, include_subfolders, filter_type, sort_method, - start_index, max_images + start_index=start_index, + max_images=num_images ) # Handle image selection if image_selected and image in image_order: start_index = image_order[image] - max_images = 1 + num_images = 1 # Create path mapping self.path_cache = { - thumb: orig for thumb, orig in zip(all_thumbnails, all_files) + thumb: orig for thumb, orig in zip(all_thumbnails, all_files[start_index:start_index + num_images]) } # Process selected range - total_files = len(all_files) - start_idx = min(max(0, start_index), total_files) - end_idx = min(start_idx + max_images, total_files) - - selected_files = all_files[start_idx:end_idx] - selected_thumbnails = all_thumbnails[start_idx:end_idx] - - # Process selected range - total_files = len(all_files) - start_idx = min(max(0, start_index), total_files) - end_idx = min(start_idx + max_images, total_files) - - selected_files = all_files[start_idx:end_idx] - selected_thumbnails = all_thumbnails[start_idx:end_idx] - + selected_files = all_files[start_index:start_index + num_images] + selected_thumbnails = all_thumbnails[:num_images] + # Process selected files images = [] masks = [] @@ -526,9 +518,9 @@ class IFLoadImagess: masks.append(mask.unsqueeze(0)) paths.append(file_path) filenames.append(os.path.basename(file_path)) - count_str = f"{idx + 1}/{total_files}" + count_str = f"{start_index + idx + 1}/{total_files}" # Update count to show global position count_strs.append(count_str) - count_ints.append(idx + 1) + count_ints.append(start_index + idx + 1) except Exception as e: logger.error(f"Error processing image {file_path}: {e}") @@ -541,10 +533,12 @@ class IFLoadImagess: ui_data = { "images": all_thumbnails, "current_thumbnails": selected_thumbnails, - "total_images": len(all_thumbnails), + "total_images": total_files, "path_mapping": self.path_cache, - "available_image_count": len(all_thumbnails), - "image_order": image_order + "available_image_count": total_files, + "image_order": image_order, + "start_index": start_index, + "stop_index": start_index + num_images } return { @@ -631,29 +625,64 @@ async def refresh_previews(request): if not data.get("input_path"): raise ValueError("No input path provided") - # Extract all parameters including max_images - max_images = data.get("max_images", None) - if max_images is not None: - max_images = int(max_images) + # Extract parameters + load_limit = int(data.get("load_limit", "1000")) + start_index = int(data.get("start_index", 0)) + stop_index = int(data.get("stop_index", 10)) + include_subfolders = data.get("include_subfolders", True) + filter_type = data.get("filter_type", "none") + sort_method = data.get("sort_method", "alphabetical") + + # Get files + if not os.path.isabs(data["input_path"]): + abs_path = os.path.abspath(os.path.join(folder_paths.get_input_directory(), data["input_path"])) + else: + abs_path = data["input_path"] + + # Get all files and sort them + all_files = ImageManager.get_image_files(abs_path, include_subfolders, filter_type) + if not all_files: + return web.json_response({ + "success": False, + "error": "No valid images found" + }) + + all_files = sorted(all_files, + key=numerical_sort_key if sort_method == "numerical" + else os.path.getctime if sort_method == "date_created" + else os.path.getmtime if sort_method == "date_modified" + else str) + + total_available = len(all_files) + + # Validate and adjust indices + start_index = min(max(0, start_index), total_available) + stop_index = min(max(start_index + 1, stop_index), total_available) + + # Calculate how many images to actually load + num_images = min(stop_index - start_index, load_limit) - # Pass max_images to create_thumbnails + # Create thumbnails only for the selected range success, message, thumbnails, image_order = ImageManager.create_thumbnails( data["input_path"], - include_subfolders=data.get("include_subfolders", True), - filter_type=data.get("filter_type", "none"), - sort_method=data.get("sort_method", "alphabetical"), - start_index=int(data.get("start_index", 0)), - max_images=max_images # Pass the limit + include_subfolders=include_subfolders, + filter_type=filter_type, + sort_method=sort_method, + start_index=start_index, + max_images=num_images # Only create thumbnails for the range we want ) return web.json_response({ "success": success, "message": message, "thumbnails": thumbnails, - "total_images": len(thumbnails), - "available_image_count": len(thumbnails), - "image_order": image_order # Include image_order in response + "total_images": total_available, + "visible_images": len(thumbnails), + "start_index": start_index, + "stop_index": stop_index, + "image_order": image_order }) + except Exception as e: logger.error(f"Error in refresh_previews route: {str(e)}") return web.json_response({ @@ -686,5 +715,5 @@ NODE_CLASS_MAPPINGS = { } NODE_DISPLAY_NAME_MAPPINGS = { - "IF_LoadImagesS": "IF Load ImagesS 🖼️" -} + "IF_LoadImagesS": "IF Load Images S 🖼️" +} \ No newline at end of file diff --git a/__init__.py b/__init__.py index 14efcc2..dd3684d 100644 --- a/__init__.py +++ b/__init__.py @@ -14,7 +14,7 @@ NODE_CLASS_MAPPINGS = { } NODE_DISPLAY_NAME_MAPPINGS = { - "IF_LoadImagesS": "IF Load ImagesS 🖼️", + "IF_LoadImagesS": "IF Load Images S 🖼️", } WEB_DIRECTORY = "./web" diff --git a/web/js/IFLoadImagesNodeS.js b/web/js/IFLoadImagesNodeS.js index eb608fd..8e9738f 100644 --- a/web/js/IFLoadImagesNodeS.js +++ b/web/js/IFLoadImagesNodeS.js @@ -170,7 +170,7 @@ app.registerExtension({ const backupBtn = this.addWidget("button", "backup_input", "Backup Input 💾", async () => { try { - const response = await api.fetchApi("/ifai/backup_input", { + const response = await api.fetchApi("/if_ai/backup_input", { method: "POST" }); @@ -192,7 +192,7 @@ app.registerExtension({ const restoreBtn = this.addWidget("button", "restore_input", "Restore Input ♻️", async () => { try { - const response = await api.fetchApi("/ifai/restore_input", { + const response = await api.fetchApi("/if_ai/restore_input", { method: "POST" }); @@ -217,37 +217,45 @@ app.registerExtension({ } ); - - // Add refresh button + // In the refresh button callback const refreshBtn = this.addWidget("button", "refresh_preview", "Refresh Previews 🔄", async () => { - // In the refresh button callback: try { const inputPath = this.widgets.find(w => w.name === "input_path")?.value; if (!inputPath) { alert("Please select a folder first"); return; } - - // Include max_images in options + + // Get widget values + const startIndexWidget = this.widgets.find(w => w.name === "start_index"); + const stopIndexWidget = this.widgets.find(w => w.name === "stop_index"); + + if (stopIndexWidget.value <= startIndexWidget.value) { + alert("Stop index must be greater than start index"); + return; + } + const options = { input_path: inputPath, include_subfolders: this.widgets.find(w => w.name === "include_subfolders")?.value ?? true, sort_method: this.widgets.find(w => w.name === "sort_method")?.value ?? "alphabetical", filter_type: this.widgets.find(w => w.name === "filter_type")?.value ?? "none", - max_images: this.widgets.find(w => w.name === "max_images")?.value + start_index: startIndexWidget.value, + stop_index: stopIndexWidget.value, + load_limit: parseInt(this.widgets.find(w => w.name === "load_limit")?.value || "1000") }; - - const response = await api.fetchApi("/ifai/refresh_previews", { + + const response = await api.fetchApi("/if_ai/refresh_previews", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(options) }); - + if (!response.ok) throw new Error(await response.text()); const result = await response.json(); if (!result.success) throw new Error(result.error); - + // Update widgets const imageWidget = this.widgets?.find(w => w.name === "image"); const availableCountWidget = this.widgets?.find(w => w.name === "available_image_count"); @@ -255,14 +263,20 @@ app.registerExtension({ if (imageWidget && result.thumbnails?.length) { imageWidget.options.values = result.thumbnails; imageWidget.value = result.thumbnails[0]; - this.imageOrder = result.image_order || {}; // Store the image order + this.imageOrder = result.image_order || {}; imageWidget.callback.call(imageWidget); } + // Update the available count if (availableCountWidget) { - availableCountWidget.value = result.available_image_count; + availableCountWidget.value = result.total_images; } - + + // Update stop_index if needed + if (result.stop_index !== stopIndexWidget.value) { + stopIndexWidget.value = result.stop_index; + } + } catch (error) { console.error("Error refreshing previews:", error); alert("Error refreshing previews: " + error.message); @@ -328,7 +342,7 @@ app.registerExtension({ nodeType.prototype.backupInputFolder = async function() { try { this.showLoader(); - const response = await fetch("/ifai/backup_input", { + const response = await fetch("/if_ai/backup_input", { method: "POST" }); @@ -351,7 +365,7 @@ app.registerExtension({ nodeType.prototype.restoreInputFolder = async function() { try { this.showLoader(); - const response = await fetch("/ifai/restore_input", { + const response = await fetch("/if_ai/restore_input", { method: "POST" }); @@ -386,7 +400,7 @@ app.registerExtension({ this.showLoader(); - const response = await fetch("/ifai/refresh_previews", { + const response = await fetch("/if_ai/refresh_previews", { method: "POST", headers: { "Content-Type": "application/json"