Merge pull request #113 from ComfyAssets/fix/custom-scan-directory-108

fix: respect custom image scan directory setting
This commit is contained in:
Vito
2026-02-09 05:50:10 -08:00
committed by GitHub
4 changed files with 150 additions and 3 deletions
+30 -2
View File
@@ -448,8 +448,15 @@ class PromptManagerAPI(
def _find_comfyui_output_dir(self):
"""Locate the ComfyUI output directory using multiple detection strategies.
Results are cached after first successful lookup since the output
directory does not change during runtime.
Checks in order:
1. User-configured directory (GalleryConfig.MONITORING_DIRECTORIES)
2. Upward filesystem search for ComfyUI markers
3. Common installation path patterns
4. Common ComfyUI installation locations
Results are cached after first successful lookup. The cache is
invalidated when the user changes the configured directory via
save_settings().
Returns:
str or None: Absolute path to ComfyUI output directory, or None
@@ -458,6 +465,27 @@ class PromptManagerAPI(
if self._cached_output_dir is not None:
return self._cached_output_dir
# Method 0: Check user-configured directory first
try:
from ..config import GalleryConfig
if GalleryConfig.MONITORING_DIRECTORIES:
configured_dir = Path(GalleryConfig.MONITORING_DIRECTORIES[0]).resolve()
if configured_dir.exists() and configured_dir.is_dir():
self.logger.info(
f"Using configured monitoring directory: {configured_dir}"
)
self._cached_output_dir = str(configured_dir)
return self._cached_output_dir
else:
self.logger.warning(
f"Configured directory does not exist: {GalleryConfig.MONITORING_DIRECTORIES[0]}"
)
except ImportError:
self.logger.debug(
"GalleryConfig not available, skipping configured directory check"
)
current_file = Path(__file__).resolve()
self.logger.debug(f"Starting ComfyUI output search from: {current_file}")
+4
View File
@@ -448,6 +448,10 @@ class AdminRoutesMixin:
GalleryConfig.MONITORING_DIRECTORIES = [new_path]
else:
GalleryConfig.MONITORING_DIRECTORIES = []
# Invalidate caches so next lookup uses new config
self._cached_output_dir = None
self._gallery_cache = None
self._gallery_cache_time = 0
restart_required = True
# Save to config file for persistence
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "promptmanager"
description = "A powerful ComfyUI custom node that extends the standard text encoder with persistent prompt storage, advanced search capabilities, and an automatic image gallery system using SQLite."
version = "3.0.36"
version = "3.0.37"
license = {file = "LICENSE"}
dependencies = ["# Core dependencies for PromptManager", "# Note: Most dependencies are already included with ComfyUI", "# Already included with Python standard library:", "# - sqlite3", "# - hashlib", "# - json", "# - datetime", "# - os", "# - typing", "# - threading", "# - uuid", "# Required for gallery functionality:", "watchdog>=2.1.0 # For file system monitoring", "Pillow>=8.0.0 # For image metadata extraction (usually included with ComfyUI)", "# Optional dependencies for enhanced search functionality:", "# fuzzywuzzy[speedup]>=0.18.0 # For fuzzy string matching (optional)", "# sqlalchemy>=1.4.0 # For advanced ORM features (optional)", "# Development dependencies (optional):", "# pytest>=6.0.0 # For running tests", "# black>=22.0.0 # For code formatting", "# flake8>=4.0.0 # For linting", "# mypy>=0.910 # For type checking"]
+115
View File
@@ -0,0 +1,115 @@
"""
Tests for _find_comfyui_output_dir() — verifies that user-configured
directories take priority over auto-detection, and that the cache is
invalidated when the setting changes.
"""
import os
import sys
import tempfile
import unittest
from pathlib import Path
from unittest.mock import MagicMock
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Mock ComfyUI's server module before importing anything that touches config
_mock_server = MagicMock()
_mock_server.PromptServer.instance.routes = MagicMock()
sys.modules["server"] = _mock_server
from py.api import PromptManagerAPI
from py.config import GalleryConfig
class TestFindComfyuiOutputDir(unittest.TestCase):
"""Test _find_comfyui_output_dir() respects user-configured directories."""
def setUp(self):
self.api = PromptManagerAPI()
self.api._cached_output_dir = None
self._orig_dirs = list(GalleryConfig.MONITORING_DIRECTORIES)
def tearDown(self):
GalleryConfig.MONITORING_DIRECTORIES = self._orig_dirs
def test_configured_directory_takes_priority(self):
"""When a valid directory is configured, it should be used instead of auto-detect."""
with tempfile.TemporaryDirectory() as tmpdir:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir]
self.api._cached_output_dir = None
result = self.api._find_comfyui_output_dir()
self.assertEqual(result, str(Path(tmpdir).resolve()))
def test_nonexistent_configured_directory_falls_through(self):
"""When the configured directory doesn't exist, fall back to auto-detection."""
GalleryConfig.MONITORING_DIRECTORIES = ["/nonexistent/fake/path/output"]
self.api._cached_output_dir = None
# Should not return the nonexistent path — will either find
# ComfyUI output via auto-detect or return None
result = self.api._find_comfyui_output_dir()
self.assertNotEqual(result, "/nonexistent/fake/path/output")
def test_empty_config_uses_auto_detection(self):
"""When MONITORING_DIRECTORIES is empty, auto-detection should be used."""
GalleryConfig.MONITORING_DIRECTORIES = []
self.api._cached_output_dir = None
# Should not raise — auto-detection may or may not find a dir
result = self.api._find_comfyui_output_dir()
# Result is either a valid path or None
if result is not None:
self.assertTrue(Path(result).is_dir())
def test_cache_returns_same_value(self):
"""After first lookup, cached value should be returned."""
with tempfile.TemporaryDirectory() as tmpdir:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir]
self.api._cached_output_dir = None
result1 = self.api._find_comfyui_output_dir()
# Change config — should NOT affect result because of cache
GalleryConfig.MONITORING_DIRECTORIES = ["/some/other/path"]
result2 = self.api._find_comfyui_output_dir()
self.assertEqual(result1, result2)
def test_cache_invalidation_picks_up_new_directory(self):
"""After clearing the cache, _find_comfyui_output_dir should use new config."""
with tempfile.TemporaryDirectory() as tmpdir1:
with tempfile.TemporaryDirectory() as tmpdir2:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir1]
self.api._cached_output_dir = None
result1 = self.api._find_comfyui_output_dir()
self.assertEqual(result1, str(Path(tmpdir1).resolve()))
# Simulate what save_settings does: update config + invalidate cache
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir2]
self.api._cached_output_dir = None
result2 = self.api._find_comfyui_output_dir()
self.assertEqual(result2, str(Path(tmpdir2).resolve()))
def test_configured_directory_is_resolved(self):
"""Configured paths with symlinks or .. should be resolved to absolute."""
with tempfile.TemporaryDirectory() as tmpdir:
# Use a relative-ish path with ..
parent = str(Path(tmpdir).parent)
basename = Path(tmpdir).name
dotdot_path = os.path.join(parent, ".", basename)
GalleryConfig.MONITORING_DIRECTORIES = [dotdot_path]
self.api._cached_output_dir = None
result = self.api._find_comfyui_output_dir()
self.assertEqual(result, str(Path(tmpdir).resolve()))
if __name__ == "__main__":
unittest.main()