diff --git a/src/comfyui_ino_nodes/s3_helper/__init__.py b/src/comfyui_ino_nodes/s3_helper/__init__.py index 6f1ac57..46ca11d 100644 --- a/src/comfyui_ino_nodes/s3_helper/__init__.py +++ b/src/comfyui_ino_nodes/s3_helper/__init__.py @@ -11,6 +11,8 @@ from .s3_download_audio_node import InoS3DownloadAudio from .s3_upload_audio_node import InoS3UploadAudio from .s3_upload_video_node import InoS3UploadVideo from .s3_verify_file_node import InoS3VerifyFile +from .s3_download_string_node import InoS3DownloadString +from .s3_download_video_node import InoS3DownloadVideo from .s3_sync_folder_node import InoS3SyncFolder LOCAL_NODE_CLASS = { @@ -24,6 +26,8 @@ LOCAL_NODE_CLASS = { "InoS3UploadString": InoS3UploadString, "InoS3GetDownloadURL": InoS3GetDownloadURL, "InoS3DownloadAudio": InoS3DownloadAudio, + "InoS3DownloadString": InoS3DownloadString, + "InoS3DownloadVideo": InoS3DownloadVideo, "InoS3UploadAudio": InoS3UploadAudio, "InoS3UploadVideo": InoS3UploadVideo, "InoS3VerifyFile": InoS3VerifyFile, @@ -40,6 +44,8 @@ LOCAL_NODE_NAME = { "InoS3UploadString": "Ino S3 Upload String", "InoS3GetDownloadURL": "Ino S3 Get Download URL", "InoS3DownloadAudio": "Ino S3 Download Audio", + "InoS3DownloadString": "Ino S3 Download String", + "InoS3DownloadVideo": "Ino S3 Download Video", "InoS3UploadAudio": "Ino S3 Upload Audio", "InoS3UploadVideo": "Ino S3 Upload Video", "InoS3VerifyFile": "Ino S3 Verify File", diff --git a/src/comfyui_ino_nodes/s3_helper/s3_download_string_node.py b/src/comfyui_ino_nodes/s3_helper/s3_download_string_node.py new file mode 100644 index 0000000..e284691 --- /dev/null +++ b/src/comfyui_ino_nodes/s3_helper/s3_download_string_node.py @@ -0,0 +1,66 @@ +import os +from pathlib import Path + +from inopyutils import ino_is_err, InoUtilHelper + +import folder_paths +from comfy_api.latest import io + +from .s3_helper import S3Helper, S3_EMPTY_CONFIG_STRING +from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path + + +class InoS3DownloadString(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="InoS3DownloadString", + display_name="Ino S3 Download String", + category="InoS3Helper", + description="Downloads a text file (txt/json/ini) from S3 and returns its content as a string.", + inputs=[ + io.Boolean.Input("enabled", default=True, label_off="OFF", label_on="ON"), + io.String.Input("s3_key", default="input/example.txt"), + io.String.Input("s3_config", default=S3_EMPTY_CONFIG_STRING, optional=True, tooltip="you can leave it empty and pass it with env vars"), + ], + outputs=[ + io.Boolean.Output(display_name="success"), + io.String.Output(display_name="message"), + io.String.Output(display_name="string"), + ], + ) + + @classmethod + async def execute(cls, enabled, s3_key, s3_config=None) -> io.NodeOutput: + if not enabled: + return io.NodeOutput(False, "not enabled", "") + + validate_s3_key = S3Helper.validate_s3_key(s3_key) + if not validate_s3_key["success"]: + return io.NodeOutput(False, validate_s3_key["msg"], "") + + temp_path = folder_paths.get_temp_directory() + save_dir = os.path.join(temp_path, "s3_download_string") + os.makedirs(save_dir, exist_ok=True) + + random_str = InoUtilHelper.get_date_time_utc_base64() + ext = Path(s3_key).suffix or ".txt" + local_file = f"{random_str}{ext}" + full_path = os.path.join(save_dir, local_file) + + s3_instance = S3Helper.get_instance(s3_config) + if ino_is_err(s3_instance): + return io.NodeOutput(False, s3_instance["msg"], "") + s3_instance = s3_instance["instance"] + + downloaded = await s3_instance.download_file(s3_key=s3_key, local_file_path=full_path) + if not downloaded["success"]: + return io.NodeOutput(False, downloaded["msg"], "") + + try: + with open(full_path, "r", encoding="utf-8") as f: + content = f.read() + except Exception as e: + return io.NodeOutput(False, f"Failed to read file: {e}", "") + + return io.NodeOutput(True, "Success", content) diff --git a/src/comfyui_ino_nodes/s3_helper/s3_download_video_node.py b/src/comfyui_ino_nodes/s3_helper/s3_download_video_node.py new file mode 100644 index 0000000..4c29276 --- /dev/null +++ b/src/comfyui_ino_nodes/s3_helper/s3_download_video_node.py @@ -0,0 +1,64 @@ +import os +from pathlib import Path + +from inopyutils import ino_is_err, InoUtilHelper + +import folder_paths +from comfy_api.latest import io + +from .s3_helper import S3Helper, S3_EMPTY_CONFIG_STRING +from ..node_helper import PARENT_FOLDER_OPTIONS, resolve_comfy_path + + +class InoS3DownloadVideo(io.ComfyNode): + @classmethod + def define_schema(cls): + return io.Schema( + node_id="InoS3DownloadVideo", + display_name="Ino S3 Download Video", + category="InoS3Helper", + description="Downloads a video file from S3 and returns it as a VIDEO type.", + inputs=[ + io.Boolean.Input("enabled", default=True, label_off="OFF", label_on="ON"), + io.String.Input("s3_key", default="input/example.mp4"), + io.Combo.Input("parent_folder", options=PARENT_FOLDER_OPTIONS, default="temp"), + io.String.Input("folder", default=""), + io.String.Input("s3_config", default=S3_EMPTY_CONFIG_STRING, optional=True, tooltip="you can leave it empty and pass it with env vars"), + ], + outputs=[ + io.Boolean.Output(display_name="success"), + io.String.Output(display_name="message"), + io.String.Output(display_name="rel_path"), + io.String.Output(display_name="abs_path"), + io.Video.Output(display_name="video"), + ], + ) + + @classmethod + async def execute(cls, enabled, s3_key, parent_folder, folder, s3_config=None) -> io.NodeOutput: + if not enabled: + return io.NodeOutput(False, "not enabled", "", "", None) + + validate_s3_key = S3Helper.validate_s3_key(s3_key) + if not validate_s3_key["success"]: + return io.NodeOutput(False, validate_s3_key["msg"], "", "", None) + + random_str = InoUtilHelper.get_date_time_utc_base64() + file_name = f'{random_str}{Path(s3_key).suffix}' + rel_path, abs_path = resolve_comfy_path(parent_folder, folder, file_name) + + Path(abs_path).parent.mkdir(parents=True, exist_ok=True) + + s3_instance = S3Helper.get_instance(s3_config) + if ino_is_err(s3_instance): + return io.NodeOutput(False, s3_instance["msg"], "", "", None) + s3_instance = s3_instance["instance"] + + downloaded = await s3_instance.download_file(s3_key=s3_key, local_file_path=abs_path) + if not downloaded["success"]: + return io.NodeOutput(False, downloaded["msg"], rel_path, abs_path, None) + + from comfy_api.latest import Input + video = Input.Video.from_path(abs_path) + + return io.NodeOutput(True, "Success", rel_path, abs_path, video)