Upadte readme

Fix DownloadFile node to fail on empty downloads
  - Add explicit User-Agent to HTTP downloads.
  - Raise errors on failed/empty downloads instead of returning silent zero tensors
This commit is contained in:
Habib
2025-12-05 15:18:09 +01:00
parent 6923000cc9
commit edd499bb43
3 changed files with 36 additions and 33 deletions
+2
View File
@@ -20,6 +20,8 @@ A single ComfyUI node to securely download an image or audio file from a URL, st
- Optional: `expect_type` (auto/image/audio) to force the expected type, `max_mb` to cap size (default 50 MB).
- Wire `IMAGE` to image nodes or `AUDIO` to audio nodes. `filepath` points to the downloaded file in ComfyUI temp.
![Download File node screenshot](./download_file_node_screenshot.png)
## Built-in safety
- HTTP/HTTPS only, blocks private/loopback hosts to reduce SSRF risk.
- Connection/read timeouts and configurable size limit.
Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

+34 -33
View File
@@ -65,7 +65,10 @@ def _validate_url(url: str) -> str:
def _download_to_temp(url: str, max_bytes: int, timeout: tuple[float, float]):
response = requests.get(url, stream=True, timeout=timeout, allow_redirects=True)
headers = {
"User-Agent": "ComfyUI-DownloadFile/1.0 (+https://github.com/serious-factory/ComfyUI-DownloadFile)"
}
response = requests.get(url, stream=True, timeout=timeout, allow_redirects=True, headers=headers)
response.raise_for_status()
content_type = response.headers.get("content-type", "").split(";")[0].strip().lower()
@@ -145,41 +148,39 @@ class DownloadFile:
empty_image = torch.zeros((1, 1, 1, 3), dtype=torch.float32)
empty_audio = {"waveform": torch.zeros((1, 1, 1)), "sample_rate": 44100}
safe_url = _validate_url(url)
timeout = (5.0, 15.0)
max_bytes = max_mb * 1024 * 1024
try:
safe_url = _validate_url(url)
timeout = (5.0, 15.0)
max_bytes = max_mb * 1024 * 1024
temp_path, content_type = _download_to_temp(safe_url, max_bytes=max_bytes, timeout=timeout)
ext = os.path.splitext(temp_path)[1].lower()
def is_image():
if expect_type == "image":
return True
if content_type in ALLOWED_IMAGE_MIMES:
return True
return ext in ALLOWED_IMAGE_EXTS
def is_audio():
if expect_type == "audio":
return True
if content_type in ALLOWED_AUDIO_MIMES:
return True
return ext in ALLOWED_AUDIO_EXTS
if is_image():
image = _load_image(temp_path)
return (image, empty_audio, temp_path, content_type or "")
if is_audio():
audio = _load_audio(temp_path)
return (empty_image, audio, temp_path, content_type or "")
raise ValueError("Unsupported file type; only image/audio are allowed")
except Exception as e:
print(f"[DownloadFile] Error: {str(e)}")
return (empty_image, empty_audio, "", "")
raise ValueError(f"DownloadFile error: {e}")
ext = os.path.splitext(temp_path)[1].lower()
def is_image():
if expect_type == "image":
return True
if content_type in ALLOWED_IMAGE_MIMES:
return True
return ext in ALLOWED_IMAGE_EXTS
def is_audio():
if expect_type == "audio":
return True
if content_type in ALLOWED_AUDIO_MIMES:
return True
return ext in ALLOWED_AUDIO_EXTS
if is_image():
image = _load_image(temp_path)
return (image, empty_audio, temp_path, content_type or "")
if is_audio():
audio = _load_audio(temp_path)
return (empty_image, audio, temp_path, content_type or "")
raise ValueError("Unsupported file type; only image/audio are allowed")
NODE_CLASS_MAPPINGS = {