diff --git a/canvas_node.py b/canvas_node.py index 09d8fa8..e131bc6 100644 --- a/canvas_node.py +++ b/canvas_node.py @@ -333,6 +333,24 @@ class CanvasNode: latest_image_path = max(image_files, key=os.path.getctime) return latest_image_path + @classmethod + def get_latest_images(cls, since_timestamp=0): + output_dir = folder_paths.get_output_directory() + files = [] + for f_name in os.listdir(output_dir): + file_path = os.path.join(output_dir, f_name) + if os.path.isfile(file_path) and file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')): + try: + mtime = os.path.getmtime(file_path) + if mtime > since_timestamp: + files.append((mtime, file_path)) + except OSError: + continue + + files.sort(key=lambda x: x[0]) + + return [f[1] for f in files] + @classmethod def get_flow_status(cls, flow_id=None): @@ -454,6 +472,30 @@ class CanvasNode: 'error': str(e) }) + @PromptServer.instance.routes.get("/layerforge/get-latest-images/{since}") + async def get_latest_images_route(request): + try: + since_timestamp = float(request.match_info.get('since', 0)) + # JS Timestamps are in milliseconds, Python's are in seconds + latest_image_paths = cls.get_latest_images(since_timestamp / 1000.0) + + images_data = [] + for image_path in latest_image_paths: + with open(image_path, "rb") as f: + encoded_string = base64.b64encode(f.read()).decode('utf-8') + images_data.append(f"data:image/png;base64,{encoded_string}") + + return web.json_response({ + 'success': True, + 'images': images_data + }) + except Exception as e: + log_error(f"Error in get_latest_images_route: {str(e)}") + return web.json_response({ + 'success': False, + 'error': str(e) + }, status=500) + @PromptServer.instance.routes.get("/ycnode/get_latest_image") async def get_latest_image_route(request): try: diff --git a/js/Canvas.js b/js/Canvas.js index 0c4d831..5dc06a5 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -459,11 +459,17 @@ export class Canvas { _addAutoRefreshToggle() { let autoRefreshEnabled = false; + let lastExecutionStartTime = 0; + + const handleExecutionStart = () => { + lastExecutionStartTime = Date.now(); + log.debug(`Execution started, timestamp set to: ${lastExecutionStartTime}`); + }; const handleExecutionSuccess = () => { if (autoRefreshEnabled) { - log.info('Auto-refresh triggered, importing latest image.'); - this.importLatestImage(); + log.info('Auto-refresh triggered, importing latest images.'); + this.canvasIO.importLatestImages(lastExecutionStartTime); } }; @@ -479,10 +485,12 @@ export class Canvas { } ); + api.addEventListener('execution_start', handleExecutionStart); api.addEventListener('execution_success', handleExecutionSuccess); this.node.onRemoved = useChainCallback(this.node.onRemoved, () => { - log.info('Node removed, cleaning up auto-refresh listener.'); + log.info('Node removed, cleaning up auto-refresh listeners.'); + api.removeEventListener('execution_start', handleExecutionStart); api.removeEventListener('execution_success', handleExecutionSuccess); }); } diff --git a/js/CanvasIO.js b/js/CanvasIO.js index 7aaa828..fd5e985 100644 --- a/js/CanvasIO.js +++ b/js/CanvasIO.js @@ -744,12 +744,7 @@ export class CanvasIO { img.src = result.image_data; }); - await this.canvas.canvasLayers.addLayerWithImage(img, { - x: 0, - y: 0, - width: this.canvas.width, - height: this.canvas.height, - }); + await this.canvas.canvasLayers.addLayerWithImage(img, {}, 'fit'); log.info("Latest image imported and placed on canvas successfully."); return true; } else { @@ -761,4 +756,39 @@ export class CanvasIO { return false; } } + + async importLatestImages(sinceTimestamp) { + try { + log.info(`Fetching latest images since ${sinceTimestamp}...`); + const response = await fetch(`/layerforge/get-latest-images/${sinceTimestamp}`); + const result = await response.json(); + + if (result.success && result.images && result.images.length > 0) { + log.info(`Received ${result.images.length} new images, adding to canvas.`); + + for (const imageData of result.images) { + const img = new Image(); + await new Promise((resolve, reject) => { + img.onload = resolve; + img.onerror = reject; + img.src = imageData; + }); + await this.canvas.canvasLayers.addLayerWithImage(img, {}, 'fit'); + } + log.info("All new images imported and placed on canvas successfully."); + return true; + + } else if (result.success) { + log.info("No new images found since last generation."); + return true; + } + else { + throw new Error(result.error || "Failed to fetch latest images."); + } + } catch (error) { + log.error("Error importing latest images:", error); + alert(`Failed to import latest images: ${error.message}`); + return false; + } + } }