refactor(core): restructure project into shared/ and nodes/ modules

This commit is contained in:
AEmotionStudio
2026-01-19 22:02:47 -08:00
parent 06d7b955f5
commit 852840dcae
24 changed files with 217 additions and 44 deletions
+48
View File
@@ -0,0 +1,48 @@
# ComfyUI-DiscordSend Bot Environment Variables
# Copy this file to .env and fill in your values
# These override settings in config.yaml
# =============================================================================
# REQUIRED
# =============================================================================
# Discord bot token from Discord Developer Portal
DISCORDBOT_DISCORD_TOKEN=your_bot_token_here
# =============================================================================
# OPTIONAL - ComfyUI Connection
# =============================================================================
# ComfyUI server URL (default: http://127.0.0.1:8188)
# DISCORDBOT_COMFYUI_URL=http://127.0.0.1:8188
# ComfyUI WebSocket URL (default: auto-derived from COMFYUI_URL)
# DISCORDBOT_COMFYUI_WS_URL=ws://127.0.0.1:8188/ws
# Request timeout in seconds (default: 30)
# DISCORDBOT_COMFYUI_TIMEOUT=30
# =============================================================================
# OPTIONAL - Database
# =============================================================================
# Database URL (default: SQLite in bot/data/bot.db)
# For PostgreSQL: postgresql+asyncpg://user:pass@localhost/dbname
# DISCORDBOT_DATABASE_URL=sqlite+aiosqlite:///bot/data/bot.db
# =============================================================================
# OPTIONAL - Defaults
# =============================================================================
# Maximum pending jobs per user (default: 3)
# DISCORDBOT_MAX_QUEUE_PER_USER=3
# Path to default workflow JSON file
# DISCORDBOT_WORKFLOW_PATH=bot/data/default_workflow_api.json
# =============================================================================
# OPTIONAL - Discord Application
# =============================================================================
# Discord application ID (for slash command registration)
# DISCORDBOT_APPLICATION_ID=your_app_id_here
+3 -3
View File
@@ -10,9 +10,9 @@ current_dir = os.path.dirname(os.path.realpath(__file__))
if current_dir not in sys.path:
sys.path.insert(0, current_dir)
# Import nodes
from discord_image_node import DiscordSendSaveImage
from discord_video_node import DiscordSendSaveVideo
# Import nodes from nodes package
from nodes.image_node import DiscordSendSaveImage
from nodes.video_node import DiscordSendSaveVideo
# Node class mappings for ComfyUI
NODE_CLASS_MAPPINGS = {
+1 -1
View File
@@ -10,7 +10,7 @@ sys.path.append(str(project_root))
from bot.config import BotConfig
from bot.bot import ComfyUIBot
from discordsend_utils.logging_config import setup_logging
from shared.logging_config import setup_logging
def main():
# Setup logging
+1 -1
View File
@@ -7,7 +7,7 @@ from pathlib import Path
from ..embeds.builders import EmbedBuilder
from ..services.permissions import require_permission, Permissions
from ...discordsend_utils.workflow_builder import WorkflowBuilder
from ...shared.workflow import WorkflowBuilder
logger = logging.getLogger(__name__)
+48
View File
@@ -0,0 +1,48 @@
# ComfyUI-DiscordSend Bot Configuration
# Copy this file to bot/config.yaml and fill in your values
# Environment variables will override these settings (see .env.example)
discord:
# Your Discord bot token (required)
# Get one at: https://discord.com/developers/applications
token: "YOUR_BOT_TOKEN_HERE"
# Your Discord application ID (optional)
# Used for slash command registration
application_id: "YOUR_APP_ID_HERE"
comfyui:
# ComfyUI server URL (default: http://127.0.0.1:8188)
url: "http://127.0.0.1:8188"
# WebSocket URL for real-time updates (auto-derived from url if not set)
# ws_url: "ws://127.0.0.1:8188/ws"
# Request timeout in seconds
timeout: 30
defaults:
# Maximum pending jobs per user per server
max_queue_per_user: 3
# How often to update progress embeds (seconds)
progress_update_interval: 2.0
# Default generation parameters
default_steps: 20
default_cfg: 7.0
default_width: 512
default_height: 512
# Path to default workflow (relative to bot/data/)
# workflow_path: "default_workflow_api.json"
database:
# Database URL (default: SQLite in bot/data/bot.db)
# For PostgreSQL: postgresql+asyncpg://user:pass@localhost/dbname
# url: "sqlite+aiosqlite:///bot/data/bot.db"
security:
# Restrict bot to specific guild IDs (empty = all guilds allowed)
allowed_guilds: []
# Example: allowed_guilds: [123456789, 987654321]
-21
View File
@@ -1,21 +0,0 @@
"""
ComfyUI-DiscordSend Utility Package
Shared utilities for Discord integration, sanitization, and GitHub CDN operations.
"""
from .sanitizer import sanitize_json_for_export
from .github_integration import update_github_cdn_urls
from .prompt_extractor import extract_prompts_from_workflow
from .discord_api import DiscordWebhookClient, validate_webhook_url, send_to_discord_with_retry
from .image_processing import tensor_to_numpy_uint8
__all__ = [
'sanitize_json_for_export',
'update_github_cdn_urls',
'extract_prompts_from_workflow',
'DiscordWebhookClient',
'validate_webhook_url',
'send_to_discord_with_retry',
'tensor_to_numpy_uint8',
]
+10
View File
@@ -0,0 +1,10 @@
"""
ComfyUI-DiscordSend Node Implementations
This package contains the ComfyUI custom nodes for sending media to Discord.
"""
from .image_node import DiscordSendSaveImage
from .video_node import DiscordSendSaveVideo
__all__ = ['DiscordSendSaveImage', 'DiscordSendSaveVideo']
@@ -17,9 +17,9 @@ from uuid import uuid4
from typing import Any, Union, List, Optional
# Import shared utilities
from discordsend_utils import (
sanitize_json_for_export,
update_github_cdn_urls,
from shared import (
sanitize_json_for_export,
update_github_cdn_urls,
extract_prompts_from_workflow,
send_to_discord_with_retry,
tensor_to_numpy_uint8
@@ -24,7 +24,7 @@ import functools
import server
# Import shared utilities
from discordsend_utils import sanitize_json_for_export, update_github_cdn_urls, send_to_discord_with_retry, tensor_to_numpy_uint8
from shared import sanitize_json_for_export, update_github_cdn_urls, send_to_discord_with_retry, tensor_to_numpy_uint8
# Define cached decorator for local use
def cached(max_size=None):
"""
@@ -47,16 +47,18 @@ def cached(max_size=None):
return decorator(func)
return decorator
# Constants and configurations
# Define constants and variables previously imported from discordsend_utils
ffmpeg_path = None
ENCODE_ARGS = ("utf-8", "ignore")
floatOrInt = ("FLOAT", "INT")
imageOrLatent = ("IMAGE", "LATENT")
BIGMAX = 1000000
has_vhs_formats = False
# Try to import ComfyUI dependencies
# Try to import ProgressBar from comfy.utils
try:
from comfy.utils import ProgressBar
except ImportError:
# Define minimal version of ProgressBar if not running in ComfyUI
class ProgressBar:
def __init__(self, total):
self.total = total
+40
View File
@@ -0,0 +1,40 @@
"""
ComfyUI-DiscordSend Shared Utilities
This package contains shared utilities used by both ComfyUI nodes and the Discord bot.
Organized into subpackages:
- discord: Discord webhook and message utilities
- media: Image and video processing utilities
- workflow: ComfyUI workflow manipulation utilities
"""
# Re-export commonly used utilities for convenience
from .workflow.sanitizer import sanitize_json_for_export
from .workflow.prompt_extractor import extract_prompts_from_workflow
from .workflow.workflow_builder import WorkflowBuilder
from .discord.webhook_client import (
DiscordWebhookClient,
validate_webhook_url,
send_to_discord_with_retry
)
from .media.image_processing import tensor_to_numpy_uint8
from .github_integration import update_github_cdn_urls
from .logging_config import setup_logging, get_logger
__all__ = [
# Workflow utilities
'sanitize_json_for_export',
'extract_prompts_from_workflow',
'WorkflowBuilder',
# Discord utilities
'DiscordWebhookClient',
'validate_webhook_url',
'send_to_discord_with_retry',
# Media utilities
'tensor_to_numpy_uint8',
# GitHub integration
'update_github_cdn_urls',
# Logging
'setup_logging',
'get_logger',
]
+21
View File
@@ -0,0 +1,21 @@
"""
Discord Integration Utilities
Provides webhook client, message building, and CDN URL handling.
"""
from .webhook_client import (
DiscordWebhookClient,
validate_webhook_url,
sanitize_webhook_for_logging,
send_to_discord_with_retry,
validate_file_for_discord
)
__all__ = [
'DiscordWebhookClient',
'validate_webhook_url',
'sanitize_webhook_for_logging',
'send_to_discord_with_retry',
'validate_file_for_discord',
]
+11
View File
@@ -0,0 +1,11 @@
"""
Media Processing Utilities
Provides image and video processing functions.
"""
from .image_processing import tensor_to_numpy_uint8
__all__ = [
'tensor_to_numpy_uint8',
]
+15
View File
@@ -0,0 +1,15 @@
"""
Workflow Manipulation Utilities
Provides sanitization, prompt extraction, and workflow building tools.
"""
from .sanitizer import sanitize_json_for_export
from .prompt_extractor import extract_prompts_from_workflow
from .workflow_builder import WorkflowBuilder
__all__ = [
'sanitize_json_for_export',
'extract_prompts_from_workflow',
'WorkflowBuilder',
]
+1 -1
View File
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock, patch
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from discordsend_utils.discord_api import send_to_discord_with_retry
from shared.discord import send_to_discord_with_retry
class TestDiscordAPI(unittest.TestCase):
"""Tests for the Discord API utility with mocked network responses."""
+1 -1
View File
@@ -13,7 +13,7 @@ sys.modules["comfy"] = MagicMock()
sys.modules["comfy.cli_args"] = MagicMock()
# Now we can safely import
from discordsend_utils.github_integration import validate_github_repo, validate_file_path, update_github_cdn_urls
from shared.github_integration import validate_github_repo, validate_file_path, update_github_cdn_urls
class TestGitHubValidation(unittest.TestCase):
+7 -7
View File
@@ -20,9 +20,9 @@ sys.modules["cv2"] = MagicMock()
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from discordsend_utils.sanitizer import sanitize_json_for_export
from discordsend_utils.discord_api import validate_webhook_url, sanitize_webhook_for_logging, send_to_discord_with_retry, DiscordWebhookClient
from discordsend_utils.github_integration import update_github_cdn_urls
from shared.workflow.sanitizer import sanitize_json_for_export
from shared.discord.webhook_client import validate_webhook_url, sanitize_webhook_for_logging, send_to_discord_with_retry, DiscordWebhookClient
from shared.github_integration import update_github_cdn_urls
class TestSanitizer(unittest.TestCase):
@@ -176,7 +176,7 @@ class TestSSRFPrevention(unittest.TestCase):
self.assertIn("Invalid webhook URL", str(cm.exception))
@patch('discordsend_utils.discord_api.requests.post')
@patch('shared.discord.webhook_client.requests.post')
def test_send_to_discord_allows_valid_url(self, mock_post):
"""Should allow valid Discord URLs."""
valid_url = "https://discord.com/api/webhooks/123/abc"
@@ -210,7 +210,7 @@ class TestWebhookSanitization(unittest.TestCase):
class TestDiscordWebhookClient(unittest.TestCase):
"""Tests for DiscordWebhookClient security features."""
@patch('discordsend_utils.discord_api.requests.post')
@patch('shared.discord.webhook_client.requests.post')
def test_exception_token_leakage(self, mock_post):
"""Should redact tokens from exception messages in last_error."""
token = "SUPER_SECRET_TOKEN"
@@ -232,8 +232,8 @@ class TestDiscordWebhookClient(unittest.TestCase):
class TestGitHubIntegration(unittest.TestCase):
"""Tests for GitHub integration security features."""
@patch('discordsend_utils.github_integration.requests.put')
@patch('discordsend_utils.github_integration.requests.get')
@patch('shared.github_integration.requests.put')
@patch('shared.github_integration.requests.get')
def test_github_token_redaction_in_response(self, mock_get, mock_put):
"""Should redact GitHub token from error messages including response text."""
token = "ghp_SECRET_TOKEN"
+1 -2
View File
@@ -6,8 +6,7 @@ import json
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from discordsend_utils.workflow_builder import WorkflowBuilder
from discordsend_utils.prompt_extractor import extract_prompts_from_workflow
from shared.workflow import WorkflowBuilder, extract_prompts_from_workflow
class TestWorkflowBuilder(unittest.TestCase):
"""Tests for the WorkflowBuilder class."""