Files
grovergol-comfyui-grover-nodes/open_path_node.py
T
2025-09-02 12:32:45 +02:00

139 lines
5.0 KiB
Python

import os
import subprocess
import platform
import folder_paths
from server import PromptServer
from aiohttp import web
import json
class OpenPathNode:
"""
A ComfyUI node that takes a path string as input and provides a button to open it in the default file explorer.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"path": ("STRING", {
"default": "",
"multiline": False,
"placeholder": "Enter file or folder path..."
}),
},
"optional": {},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("path",)
FUNCTION = "open_path"
CATEGORY = "Grover/System"
OUTPUT_NODE = True
def open_path(self, path):
"""Process the path and return it (the button action is handled on the frontend)"""
return (path,)
@staticmethod
def open_file_explorer(path):
"""Open the given path in the default file explorer"""
try:
# Normalize the path
normalized_path = os.path.normpath(path)
# Check if path exists
if not os.path.exists(normalized_path):
print(f"Path does not exist: {normalized_path}")
return False
# Get the system platform
system = platform.system()
if system == "Windows":
# Windows - use explorer
# Note: Don't use check=True as explorer can return non-zero exit codes even on success
if os.path.isfile(normalized_path):
# If it's a file, select it in explorer
result = subprocess.run(
['explorer', '/select,', normalized_path], capture_output=True)
# For files, we can check if explorer process started successfully
# Only treat severe errors (>1) as failures
if result.returncode > 1:
print(
f"Explorer returned code {result.returncode} for file: {normalized_path}")
print(
f"stderr: {result.stderr.decode() if result.stderr else 'None'}")
return False
else:
# If it's a directory, open it
result = subprocess.run(
['explorer', normalized_path], capture_output=True)
# For directories, explorer often returns 1 even on success, so only fail on severe errors
# Only treat severe errors (>1) as failures
if result.returncode > 1:
print(
f"Explorer returned code {result.returncode} for directory: {normalized_path}")
print(
f"stderr: {result.stderr.decode() if result.stderr else 'None'}")
return False
elif system == "Darwin": # macOS
# macOS - use open command
subprocess.run(['open', normalized_path], check=True)
elif system == "Linux":
# Linux - try various file managers
try:
subprocess.run(['xdg-open', normalized_path], check=True)
except FileNotFoundError:
# Fallback to other common file managers
for fm in ['nautilus', 'dolphin', 'thunar', 'pcmanfm']:
try:
subprocess.run([fm, normalized_path], check=True)
break
except FileNotFoundError:
continue
else:
print("No suitable file manager found for Linux")
return False
else:
print(f"Unsupported operating system: {system}")
return False
return True
except Exception as e:
print(f"Error opening path '{path}': {str(e)}")
return False
# Web endpoint for handling button clicks
@PromptServer.instance.routes.post("/grover/open_path")
async def open_path_endpoint(request):
"""Handle the open path button click from the frontend"""
try:
data = await request.json()
path = data.get("path", "")
if not path:
return web.json_response({"success": False, "error": "No path provided"})
success = OpenPathNode.open_file_explorer(path)
if success:
return web.json_response({"success": True, "message": f"Opened path: {path}"})
else:
return web.json_response({"success": False, "error": f"Failed to open path: {path}"})
except Exception as e:
return web.json_response({"success": False, "error": str(e)})
# Node registration
NODE_CLASS_MAPPINGS = {
"OpenPathNode": OpenPathNode
}
NODE_DISPLAY_NAME_MAPPINGS = {
"OpenPathNode": "📁 Open Path"
}