diff --git a/__init__.py b/__init__.py index a69e2e4..873862f 100644 --- a/__init__.py +++ b/__init__.py @@ -7,6 +7,7 @@ from aiohttp import web from .src.config_reader import ConfigReader from .src.save_preview_image import SavePreviewImage +from .src.util import get_preview_image_path WEB_DIRECTORY = "./web" API_PREFIX = "/SyntaxHighlighting" @@ -19,47 +20,57 @@ NODE_DISPLAY_NAME_MAPPINGS = { } +image_index = {} + + +def load_image_index(): + images_dir = Path(get_preview_image_path()) + json_path = images_dir.joinpath("images.json") + if not json_path.exists(): + return {} + with open(json_path, "r", encoding="utf-8") as f: + data = json.load(f) + return {img["filename"]: img["path"] for img in data.get("images", [])} + + +def reload_image_index(): + global image_index + image_index.clear() + image_index.update(load_image_index()) + + def index_images(): """ Create a JSON index of all images in the web/images directory and its subfolders. """ try: - # Get the script's directory and construct path to images using Path - script_dir = Path(os.path.dirname(os.path.realpath(__file__))) - images_dir = script_dir.joinpath("web", "images") - - # Ensure directory exists + images_dir = Path(get_preview_image_path()) if not images_dir.exists(): print(f"Warning: Directory not found: {images_dir}") return {"success": False} - # Get all image files recursively image_files = [] for ext in [".png", ".jpg", ".jpeg", ".webp"]: image_files.extend(images_dir.rglob(f"*{ext}")) + print(f"Found {len(image_files)} images in {images_dir}") - # Create image entries images = [] for img_path in image_files: images.append( { "filename": img_path.stem, - "path": str(img_path.relative_to(script_dir)).replace( - "web", "extensions\\ComfyUI-Syntax-Highlight" - ), + "path": str(img_path), } ) - # Create output data output = {"images": images, "count": len(images)} - - # Write JSON file json_path = images_dir.joinpath("images.json") with open(json_path, "w", encoding="utf-8") as f: json.dump(output, f, indent=2) print(f"Created index with {len(images)} images at {json_path}") return_data = {"success": True, "count": len(images)} + reload_image_index() return return_data except Exception as e: @@ -67,7 +78,6 @@ def index_images(): return {"success": False} -# Create image index index_images() @@ -91,6 +101,7 @@ async def get_enabled(request): @PromptServer.instance.routes.get(f"{API_PREFIX}/index") async def index_images_endpoint(request): data = index_images() + reload_image_index() return web.json_response(data) @@ -98,3 +109,24 @@ async def index_images_endpoint(request): async def favorites_endpoint(request): favorites = ConfigReader.get_setting("SyntaxHighlighting.favorites", []) return web.json_response({"favorites": favorites}) + + +@PromptServer.instance.routes.get(f"{API_PREFIX}/images_json") +async def serve_images_json(request): + images_dir = Path(get_preview_image_path()) + json_path = images_dir.joinpath("images.json") + if json_path.exists(): + return web.FileResponse(path=json_path) + return web.Response(status=404, text="images.json not found") + + +@PromptServer.instance.routes.get(f"{API_PREFIX}/images/{{filename}}") +async def serve_image(request): + filename = request.match_info["filename"] + if not filename: + return web.Response(status=400, text="Filename is required") + + img_path = image_index.get(filename) + if img_path and Path(img_path).exists(): + return web.FileResponse(path=img_path) + return web.Response(status=404, text="Image not found") diff --git a/src/save_preview_image.py b/src/save_preview_image.py index 913de22..296a705 100644 --- a/src/save_preview_image.py +++ b/src/save_preview_image.py @@ -6,26 +6,19 @@ import folder_paths from PIL import Image from PIL.PngImagePlugin import PngInfo from comfy.cli_args import args +from .util import get_preview_image_path class SavePreviewImage: def __init__(self): self.type = "temp" self.compress_level = 4 - base_dir = self.get_base_dir() - self.output_dir = os.path.join(base_dir, "web/images") + self.output_dir = get_preview_image_path() os.makedirs(self.output_dir, exist_ok=True) self.temp_output_dir = folder_paths.get_temp_directory() self.prefix_append = "_temp_" + "".join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5)) - @classmethod - def get_base_dir(cls): - dir_path = os.path.dirname(os.path.realpath(__file__)) - if os.path.basename(dir_path) == "src": - dir_path = os.path.dirname(dir_path) - return dir_path - @classmethod def INPUT_TYPES(s): return { diff --git a/src/util.py b/src/util.py new file mode 100644 index 0000000..c699226 --- /dev/null +++ b/src/util.py @@ -0,0 +1,21 @@ +import os +from .config_reader import ConfigReader + + +def get_preview_image_path(): + path: str = ConfigReader.get_setting("SyntaxHighlighting.preview-image-save-path", "./web/images") + base_dir = get_base_dir() + + if path.startswith("./"): + path = os.path.join(base_dir, path[2:]) + else: + path = os.path.abspath(path) + + return path + + +def get_base_dir(): + dir_path = os.path.dirname(os.path.realpath(__file__)) + if os.path.basename(dir_path) == "src": + dir_path = os.path.dirname(dir_path) + return dir_path diff --git a/web/js/favorite.js b/web/js/favorite.js index f5ad056..61c9329 100644 --- a/web/js/favorite.js +++ b/web/js/favorite.js @@ -1,9 +1,8 @@ -import { SettingsHelper } from "./settings/ComfyHelper.js"; +import { settingsHelper, API_PREFIX } from "./settings.js"; import { hexToRgb, leadingEdgeDebounce } from "./util.js"; import { app } from "../../../scripts/app.js"; import { api } from "../../../scripts/api.js"; -const settingsHelper = new SettingsHelper("SyntaxHighlighting"); let contextMenuObserver = null; let favoritesCache = null; @@ -428,9 +427,9 @@ async function observeContextMenu(existingList) { document.head.appendChild(style); let images; try { - images = await fetch( - "/extensions/ComfyUI-Syntax-Highlight/images/images.json" - ).then((response) => response.json()); + images = await fetch(`${API_PREFIX}/images_json`).then((response) => + response.json() + ); } catch (error) { console.error("Error fetching images.json:", error); images = { images: [] }; @@ -483,7 +482,7 @@ async function addPreviewImage(entry, path, settings) { // Create temporary image to get dimensions const tempImg = new Image(); - tempImg.src = path; + tempImg.src = `${API_PREFIX}/images/${path.split("/").pop().split(".")[0]}`; // Wait for image to load to get actual dimensions await new Promise((resolve) => { @@ -717,7 +716,7 @@ async function addPreviewImage(entry, path, settings) { // Create and position the actual preview image const preview = document.createElement("img"); preview.className = "preview-image"; - preview.src = path; + preview.src = `${API_PREFIX}/images/${path.split("/").pop().split(".")[0]}`; preview.style.maxWidth = `${maxSize}px`; preview.style.maxHeight = `${maxSize}px`; preview.style.position = "fixed"; diff --git a/web/js/settings.js b/web/js/settings.js index ef57ed4..1132f03 100644 --- a/web/js/settings.js +++ b/web/js/settings.js @@ -47,6 +47,17 @@ const settingsDefinitions = [ type: SettingsHelper.ST.COLORPICKER, onChange: () => SettingsHelper.PresetOnChange.reloadSettings(), }, + { + name: "Preview Image Save Path", + category: [ + "Syntax Highlighting", + "Preview Image", + "PreviewImageSavePath", + ], + defaultValue: "./web/images", + type: SettingsHelper.ST.TEXT, + onChange: () => SettingsHelper.PresetOnChange.reloadSettings(), + }, { name: "Preview Image Hover Delay", category: ["Syntax Highlighting", "Preview Image", "PreviewImageDelay"],