diff --git a/README.ZH_CN.md b/README.ZH_CN.md index 5118bb5..3643100 100644 --- a/README.ZH_CN.md +++ b/README.ZH_CN.md @@ -21,6 +21,8 @@ git clone https://github.com/1hew/ComfyUI-1hewNodes ## 📜 更新 +**v1.2.36** +- feat(conversion): 增强 `URL to Video` 节点 **v1.2.35** - feat(image): 添加 `Image Resize Qwen Image` 节点,专为 Qwen 视觉模型优化的图像缩放器,提供 7 种预设分辨率和自动宽高比选择 @@ -233,8 +235,9 @@ git clone https://github.com/1hew/ComfyUI-1hewNodes | Image List to Batch | 将图像列表转换为批量图像,自动进行尺寸标准化 | | Mask Batch to List | 将批量遮罩转换为遮罩列表,用于单独处理 | | Mask List to Batch | 将遮罩列表转换为批量遮罩,自动进行尺寸标准化 | -| String Coordinate to BBoxes | 将字符串格式坐标转换为BBOXES格式,支持多种输入格式 | +| String Coordinate to BBoxes | 将字符串格式坐标转换为BBOXES格式,增强格式支持并改进SAM2兼容性 | | String Coordinate to BBox Mask | 将字符串格式坐标转换为BBoxMask格式,支持图像尺寸获取和灵活的输出模式 | +| URL to Video | 将视频URL转换为ComfyUI VIDEO对象,改进错误处理、超时控制,支持同步和异步下载方法 | ### 🧠 逻辑节点 | 节点名称 | 功能描述 | diff --git a/README.md b/README.md index 09ef6d7..4391469 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ git clone https://github.com/1hew/ComfyUI-1hewNodes ## 📜 Changelog +**v1.2.36** +- feat(conversion): Enhanced `URL to Video` node + **v1.2.35** - feat(image): Added `Image Resize Qwen Image` node for Qwen vision model optimized image resizing with 7 preset resolutions and automatic aspect ratio selection @@ -233,8 +236,9 @@ git clone https://github.com/1hew/ComfyUI-1hewNodes | Image List to Batch | Convert image lists to batch images with automatic size normalization | | Mask Batch to List | Convert batch masks to mask lists for individual processing | | Mask List to Batch | Convert mask lists to batch masks with automatic size normalization | -| String Coordinate to BBoxes | Convert string format coordinates to BBOXES format with multiple input format support | +| String Coordinate to BBoxes | Convert string format coordinates to BBOXES format with enhanced format support and improved SAM2 compatibility | | String Coordinate to BBox Mask | Convert string format coordinates to BBoxMask format with image dimension support and flexible output modes | +| URL to Video | Convert video URLs to ComfyUI VIDEO objects with improved error handling, timeout control, and support for both synchronous and asynchronous download methods | ### 🧠 Logic Nodes | Node Name | Description | diff --git a/nodes/conversion.py b/nodes/conversion.py index 6b53c4d..d33fe58 100644 --- a/nodes/conversion.py +++ b/nodes/conversion.py @@ -2,7 +2,164 @@ import json import ast import re import torch -from typing import List, Dict, Any, Union +import io +import asyncio +import aiohttp +import requests +import logging +from typing import List, Dict, Any, Union, Optional + +# 尝试导入ComfyUI VIDEO类型 +try: + from comfy_api.input_impl import VideoFromFile + from comfy_api.latest import io as comfy_io + COMFYUI_VIDEO_AVAILABLE = True +except ImportError: + try: + from comfy_api.input_impl.video_types import VideoFromFile + COMFYUI_VIDEO_AVAILABLE = True + except ImportError: + COMFYUI_VIDEO_AVAILABLE = False + logging.warning("ComfyUI VIDEO types not available, using fallback implementation") + + +class URLToVideo: + """ + 将视频URL转换为ComfyUI VIDEO对象 + """ + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "video_url": ("STRING", { + "default": "", + "multiline": False, + "tooltip": "视频文件的URL地址" + }), + }, + "optional": { + "timeout": ("INT", { + "default": 30, + "min": 5, + "max": 300, + "step": 1, + "tooltip": "下载超时时间(秒)" + }), + "use_async": ("BOOLEAN", { + "default": False, + "tooltip": "是否使用异步下载(推荐用于大文件)" + }), + } + } + + RETURN_TYPES = ("VIDEO",) if COMFYUI_VIDEO_AVAILABLE else ("STRING",) + RETURN_NAMES = ("video",) if COMFYUI_VIDEO_AVAILABLE else ("error_message",) + FUNCTION = "convert_url_to_video" + CATEGORY = "1hewNodes/conversion" + + def download_video_from_url_sync(self, video_url: str, timeout: int = 30) -> Optional[io.BytesIO]: + """同步下载视频文件""" + try: + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' + } + + response = requests.get(video_url, headers=headers, timeout=timeout, stream=True) + response.raise_for_status() + + video_data = io.BytesIO() + for chunk in response.iter_content(chunk_size=8192): + if chunk: + video_data.write(chunk) + + video_data.seek(0) + return video_data + + except Exception as e: + logging.error(f"同步下载视频失败: {str(e)}") + return None + + async def download_video_from_url_async(self, video_url: str, timeout: int = 30) -> Optional[io.BytesIO]: + """异步下载视频文件""" + try: + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' + } + + timeout_config = aiohttp.ClientTimeout(total=timeout) + async with aiohttp.ClientSession(timeout=timeout_config) as session: + async with session.get(video_url, headers=headers) as response: + response.raise_for_status() + + video_data = io.BytesIO() + async for chunk in response.content.iter_chunked(8192): + video_data.write(chunk) + + video_data.seek(0) + return video_data + + except Exception as e: + logging.error(f"异步下载视频失败: {str(e)}") + return None + + def convert_url_to_video(self, video_url: str, timeout: int = 30, use_async: bool = False): + """将视频URL转换为ComfyUI VIDEO对象""" + if not video_url or not video_url.strip(): + error_msg = "视频URL不能为空" + if COMFYUI_VIDEO_AVAILABLE: + raise ValueError(error_msg) + else: + return (error_msg,) + + # 验证URL格式 + if not video_url.startswith(('http://', 'https://')): + error_msg = "无效的URL格式,必须以http://或https://开头" + if COMFYUI_VIDEO_AVAILABLE: + raise ValueError(error_msg) + else: + return (error_msg,) + + try: + # 下载视频数据 + if use_async: + # 在同步环境中运行异步函数 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + video_data = loop.run_until_complete( + self.download_video_from_url_async(video_url, timeout) + ) + finally: + loop.close() + else: + video_data = self.download_video_from_url_sync(video_url, timeout) + + if video_data is None: + error_msg = "视频下载失败" + if COMFYUI_VIDEO_AVAILABLE: + raise RuntimeError(error_msg) + else: + return (error_msg,) + + # 如果ComfyUI VIDEO类型不可用,返回成功消息 + if not COMFYUI_VIDEO_AVAILABLE: + return ("视频下载成功,但ComfyUI VIDEO类型不可用",) + + # 创建ComfyUI VIDEO对象 + try: + video_object = VideoFromFile(video_data) + return (video_object,) + except Exception as e: + raise RuntimeError(f"创建VIDEO对象失败: {str(e)}") + + except Exception as e: + error_msg = f"URL转换视频失败: {str(e)}" + logging.error(error_msg) + if COMFYUI_VIDEO_AVAILABLE: + raise RuntimeError(error_msg) + else: + return (error_msg,) class ImageBatchToList: @@ -357,6 +514,7 @@ class StringCoordinateToBBoxMask: # 节点映射 NODE_CLASS_MAPPINGS = { + "URLToVideo": URLToVideo, "ImageBatchToList": ImageBatchToList, "ImageListToBatch": ImageListToBatch, "MaskBatchToList": MaskBatchToList, @@ -366,6 +524,7 @@ NODE_CLASS_MAPPINGS = { } NODE_DISPLAY_NAME_MAPPINGS = { + "URLToVideo": "URL to Video", "ImageBatchToList": "Image Batch to List", "ImageListToBatch": "Image List to Batch", "MaskBatchToList": "Mask Batch to List", diff --git a/pyproject.toml b/pyproject.toml index 00b42e7..78af50f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "ComfyUI-1hewNodes" description = "This is a custom node collection for ComfyUI that provides some utility nodes." -version = "1.2.35" +version = "1.2.36" license = {file = "LICENSE"} [project.urls] diff --git a/web/docs/StringCoordinateToBBoxes/en.md b/web/docs/StringCoordinateToBBoxes/en.md index 2176496..645180b 100644 --- a/web/docs/StringCoordinateToBBoxes/en.md +++ b/web/docs/StringCoordinateToBBoxes/en.md @@ -1,15 +1,15 @@ # String Coordinate to BBoxes -**Node Function:** The `String Coordinate to BBoxes` node converts string format coordinate lists to BBOXES format, supporting multiple input formats like "x1,y1,x2,y2" or "[x1,y1,x2,y2]" or multi-line coordinates, commonly used for coordinate data conversion and SAM2 compatibility. +**Node Function:** The `String Coordinate to BBoxes` node converts string format coordinate lists to BBOXES format, supporting multiple input formats including "[x1,y1,x2,y2]" or multi-line coordinates for SAM2 compatibility. ## Inputs | Parameter | Required | Data Type | Default | Range | Description | -| --------- | -------- | --------- | ------- | ----- | ----------- | -| `coordinates_string` | Required | STRING | "" | Multi-line text | Coordinate string input, supports "[x1,y1,x2,y2]" or multi-line coordinates | +|--|--|--|--|--|--| +| `coordinates_string` | Required | STRING | "" | Multi-line text | String format coordinates supporting "[x1,y1,x2,y2]" or multi-line coordinates | ## Outputs | Output Name | Data Type | Description | |-------------|-----------|-------------| -| `bboxes` | BBOXES | Converted bounding boxes in SAM2 compatible format | \ No newline at end of file +| `bboxes` | BBOXES | SAM2 compatible bounding boxes format | diff --git a/web/docs/StringCoordinateToBBoxes/zh.md b/web/docs/StringCoordinateToBBoxes/zh.md index b23561e..f8e888c 100644 --- a/web/docs/StringCoordinateToBBoxes/zh.md +++ b/web/docs/StringCoordinateToBBoxes/zh.md @@ -1,15 +1,15 @@ # String Coordinate to BBoxes - 字符串坐标转边界框 -**节点功能:** `String Coordinate to BBoxes`节点将字符串格式的坐标列表转换为BBOXES格式,支持多种输入格式如"x1,y1,x2,y2"或"[x1,y1,x2,y2]"或多行坐标,常用于坐标数据转换和SAM2兼容性处理。 +**节点功能:** `String Coordinate to BBoxes`节点将字符串格式的坐标列表转换为BBOXES格式,支持多种输入格式包括"[x1,y1,x2,y2]"或多行坐标,用于SAM2兼容性。 ## 输入 | 参数名称 | 入端选择 | 数据类型 | 默认值 | 取值范围 | 描述 | | -------- | -------- | -------- | ------ | -------- | ---- | -| `coordinates_string` | 必选 | STRING | "" | 多行文本 | 坐标字符串输入,支持"[x1,y1,x2,y2]"或多行坐标格式 | +| `coordinates_string` | 必选 | STRING | "" | 多行文本 | 字符串格式坐标,支持"[x1,y1,x2,y2]"或多行坐标 | ## 输出 | 输出名称 | 数据类型 | 描述 | |---------|----------|------| -| `bboxes` | BBOXES | 转换后的SAM2兼容格式边界框 | \ No newline at end of file +| `bboxes` | BBOXES | SAM2兼容的边界框格式 | \ No newline at end of file diff --git a/web/docs/URLToVideo/en.md b/web/docs/URLToVideo/en.md new file mode 100644 index 0000000..356bdd0 --- /dev/null +++ b/web/docs/URLToVideo/en.md @@ -0,0 +1,18 @@ +# URL to Video + +**Node Function:** The `URL to Video` node converts video URLs to ComfyUI VIDEO objects, supporting both synchronous and asynchronous download methods with comprehensive error handling and timeout control. + +## Inputs + +| Parameter | Required | Data Type | Default | Range | Description | +|--|--|--|--|--|--| +| `video_url` | Required | STRING | "" | - | Video file URL address | +| `timeout` | - | INT | 30 | 5-300 | Download timeout in seconds | +| `use_async` | - | BOOLEAN | False | True/False | Whether to use asynchronous download (recommended for large files) | + +## Outputs + +| Output Name | Data Type | Description | +|-------------|-----------|-------------| +| `video` | VIDEO | ComfyUI VIDEO object (when VIDEO types available) | +| `error_message` | STRING | Error message (when VIDEO types unavailable) | \ No newline at end of file diff --git a/web/docs/URLToVideo/zh.md b/web/docs/URLToVideo/zh.md new file mode 100644 index 0000000..fd761c2 --- /dev/null +++ b/web/docs/URLToVideo/zh.md @@ -0,0 +1,18 @@ +# URL to Video - URL转视频 + +**节点功能:** `URL to Video`节点将视频URL转换为ComfyUI VIDEO对象,支持同步和异步下载方法,具备完善的错误处理和超时控制功能。 + +## 输入 + +| 参数名称 | 入端选择 | 数据类型 | 默认值 | 取值范围 | 描述 | +| -------- | -------- | -------- | ------ | -------- | ---- | +| `video_url` | 必选 | STRING | "" | - | 视频文件的URL地址 | +| `timeout` | - | INT | 30 | 5-300 | 下载超时时间(秒) | +| `use_async` | - | BOOLEAN | False | True/False | 是否使用异步下载(推荐用于大文件) | + +## 输出 + +| 输出名称 | 数据类型 | 描述 | +|---------|----------|------| +| `video` | VIDEO | ComfyUI VIDEO对象(当VIDEO类型可用时) | +| `error_message` | STRING | 错误信息(当VIDEO类型不可用时) | \ No newline at end of file