From fe0f05bee844f0505709f8d9de83beaaa0cf339b Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Mon, 21 Jul 2025 09:11:03 -0300 Subject: [PATCH] [Nodes] Moved the image downloader To ComfyUI-ImageMisc --- README.md | 31 ++--------- source/nodes/nodes_audio.py | 103 ------------------------------------ 2 files changed, 5 insertions(+), 129 deletions(-) diff --git a/README.md b/README.md index fd34ff1..acf1e65 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,6 @@ workflows, especially when dealing with multiple audio inputs or outputs. - [15. Audio Normalize (Peak)](#15-audio-normalize-peak) - [16. Audio Apply Batched Gain](#16-audio-apply-batched-gain) - [17. Audio Download and Load](#17-audio-download-and-load) -- ✨ [Extra nodes](#-extra-nodes) - - [1. Image Download and Load](#1-image-download-and-load) - 📝 [Usage Notes](#-usage-notes) - 🛠️ [Future Improvements / TODO](#️-future-improvements--todo) - 📜 [Project History](#-project-history) @@ -323,28 +321,6 @@ workflows, especially when dealing with multiple audio inputs or outputs. - **Player**: This node uses an `AUDIO_UI` widget to allow playing the downloaded song. -## ✨ Extra nodes - -These nodes are just complements for the other nodes. I.e. they share a lot of code. - -### 1. Image Download and Load - - **Display Name:** `Image Download and Load` - - **Internal Name:** `SET_ImageDownload` - - **Category:** `image/io` - - **Description:** Downloads an image file from a URL into the `ComfyUI/input/` directory if it's not already there, and then loads it as an image and mask. This is perfect for creating self-contained, shareable workflows with example image. - - **Inputs:** - - `image_bypass` (IMAGE, Optional): If an image is provided here it will be used for the output. You can connect a `Load Image` node here, if the connected node is muted (bypassed) we download the file, otherwise we use the image from the `Load Image` node. - - `mask_bypass` (MASK, Optional): This input complements `image_bypass`. - - `base_url` (STRING): The URL of the directory containing the image file. - - `filename` (STRING): The name of the image file to download (e.g., photo.jpg, art.png). - - **Output:** - - `image` (IMAGE): The loaded image. - - `alpha_mask` (MASK): The alpha mask for the loaded image. - - **Behavior Details:** - - **Caching:** The node checks the `ComfyUI/input/` folder first. If the file with the specified `filename` already exists, the download is skipped. - - **Bypass:** If only one of `image_bypass` and `mask_bypass` is connected the other will be assumed to be empty. You should connect both or avoid using the output corresponding to the unconnected input. - - ## 🚀 Installation You can install the nodes from the ComfyUI nodes manager, the name is *Audio Batch*, or just do it manually: @@ -356,19 +332,22 @@ You can install the nodes from the ComfyUI nodes manager, the name is *Audio Bat ``` 2. Restart ComfyUI. -The nodes should then appear under the "audio/batch" and "audio/conversion" categories in the "Add Node" menu. +The nodes should then appear under the "audio/batch", "audio/conversion","audio/manipulation", "audio/generation" and "audio/io" categories in the "Add Node" menu. + ## 📦 Dependencies - PyTorch - Torchaudio (for resampling and potentially other audio operations) - NumPy (often used with audio data) +- Requests (optional): Usually an indirect ComfyUI dependency. If installed it will be used for downloads, it should be more robust than then built-in `urllib`, used as fallback. +- Colorama (optional): Might help to get colored log messages on some terminals. We use ANSI escape sequences when it isn't installed. These are typically already present in a standard ComfyUI environment. ## 🖼️ Examples -Once installed the examples are available in the ComfyUI workflow templates, in the *Audio Batch* section. +Once installed the examples are available in the ComfyUI workflow templates, in the *Audio Batch* section (or ComfyUI-AudioBatch). - [audio_batch_select_example.json](example_workflows/audio_batch_select_example.json): Shows how to create a batch and how to extract a single element from the batch. diff --git a/source/nodes/nodes_audio.py b/source/nodes/nodes_audio.py index 464f2b3..ae2ee6f 100644 --- a/source/nodes/nodes_audio.py +++ b/source/nodes/nodes_audio.py @@ -21,12 +21,6 @@ except ModuleNotFoundError: # No ComfyUI, this is a test environment def get_input_directory(): return "" -try: - # We need to import the built-in LoadImage class for ImageDownload - from nodes import LoadImage # type: ignore[attr-defined] - has_load_image = True -except Exception: - has_load_image = False logger = main_logger BASE_CATEGORY = "audio" @@ -1149,100 +1143,3 @@ class AudioDownload: except Exception as e: logger.error(f"Failed to load or process audio file '{local_filepath}': {e}", exc_info=True) raise IOError(f"Could not load or process the audio file: {filename}. It may be missing or corrupt.") from e - - -if has_load_image: - class ImageDownload: - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "base_url": ("STRING", { - "default": - "https://raw.githubusercontent.com/set-soft/AudioSeparation/refs/heads/main/example_workflows/", - "tooltip": "The base URL where the image file is located." - }), - "filename": ("STRING", { - "default": "audioseparation_logo.jpg", - "tooltip": "The name of the image file to download (e.g., photo.jpg, art.png)." - }), - }, - "optional": { - "image_bypass": ("IMAGE", { - "tooltip": "If this image is present will be used instead of the downloaded one" - }), - "mask_bypass": ("MASK", {"tooltip": "If this mask is present will be used instead of the downloaded one"}), - } - } - - RETURN_TYPES = ("IMAGE", "MASK") - RETURN_NAMES = ("image", "alpha_mask") - FUNCTION = "load_or_download_image" - CATEGORY = "image" + "/" + IO_CATEGORY - DESCRIPTION = ("Downloads an image to ComfyUI's 'input' directory if it doesn't exist, then loads it using the " - "built-in LoadImage logic.") - UNIQUE_NAME = "SET_ImageDownload" - DISPLAY_NAME = "Image Download and Load" - OUTPUT_NODE = True - - def load_or_download_image(self, base_url: str, filename: str, image_bypass: Optional[torch.Tensor] = None, - mask_bypass: Optional[torch.Tensor] = None): - # If we have something at the bypass inputs use it - if image_bypass is not None or mask_bypass is not None: - if image_bypass is None: - # Just a mask - assert mask_bypass is not None, "This should not be possible if image_bypass is None" # For mypy - image_bypass = torch.zeros(mask_bypass.shape + (3,), dtype=torch.float32, device="cpu") - logger.warning("ImageDownload: Returning an empty image") - elif mask_bypass is None: - # This is ComfyUI behavior when we don't have transparency - mask_bypass = torch.zeros((64, 64), dtype=torch.float32, device="cpu").unsqueeze(0) - logger.warning("ImageDownload: Returning an empty mask") - return (image_bypass, mask_bypass) - - save_dir = get_input_directory() - local_filepath = os.path.join(save_dir, filename) - - if not os.path.exists(local_filepath): - logger.info(f"File '{filename}' not found locally. Attempting to download.") - - if not base_url.endswith('/'): - base_url += '/' - download_url = base_url + filename - - try: - download_model(url=download_url, save_dir=save_dir, file_name=filename, kind="image") - except Exception as e: - logger.error(f"Download failed for {download_url}: {e}", exc_info=True) - raise - - else: - logger.info(f"Found existing file, skipping download: '{local_filepath}'") - - # --- REUSE ComfyUI's LoadImage LOGIC --- - try: - # Instantiate the built-in LoadImage node - loader_instance = LoadImage() - - # The LoadImage node's `load_image` method expects the filename as passed - # by the ComfyUI widget, which is just the filename. It internally - # resolves the path using folder_paths. - - logger.debug(f"Calling built-in LoadImage.load_image() with filename: '{filename}'") - - # Call the method and return its result directly - result = loader_instance.load_image(filename) - downloaded_file = { - "images": [{ - "filename": filename, - "subfolder": "", - "type": "input" # We stored the file in the "input" folder - }] - } - return {"ui": downloaded_file, "result": result} - - except Exception as e: - logger.error(f"Failed to load image '{filename}' using built-in LoadImage node: {e}", exc_info=True) - # Re-raise to make the error visible in ComfyUI - raise IOError(f"Could not load the image file '{filename}' using the standard loader. " - "It may be corrupt or in an unsupported format.") from e