From 0c0cd1dca3f08bdd3a54caeeee929a16e93523a1 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 2 Apr 2026 21:20:41 +0100 Subject: [PATCH] works --- web/power_load_video/power_load_video.js | 177 +++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/web/power_load_video/power_load_video.js b/web/power_load_video/power_load_video.js index e4ec38f..bfb7abc 100644 --- a/web/power_load_video/power_load_video.js +++ b/web/power_load_video/power_load_video.js @@ -115,6 +115,140 @@ app.registerExtension({ return null; }; + /** + * Upload an image file to ComfyUI's input directory + */ + const uploadImageFile = async (file) => { + const formData = new FormData(); + formData.append('image', file); + formData.append('type', 'input'); + + try { + const resp = await api.fetchApi('/upload/image', { method: 'POST', body: formData }); + if (resp.ok || resp.status === 200) { + const data = await resp.json(); + return data.name || data.filename || file.name; + } + } catch (err) { + console.error('[PowerLoadVideo] Image upload error:', err); + } + return null; + }; + + /** + * Create a LoadImage node at the given position and load an image into it + */ + const createLoadImageNodeWithImage = async (filename, pos) => { + // Check if LoadImage node type exists + if (!LiteGraph.registered_node_types['LoadImage']) { + console.error('[PowerLoadVideo] LoadImage node type not found!'); + return null; + } + + const node = LiteGraph.createNode('LoadImage'); + if (!node) { + console.error('[PowerLoadVideo] Failed to create LoadImage node!'); + return null; + } + + // Set position centered at mouse + node.pos = [pos[0] - 150, pos[1] - 100]; + + // Add node to graph + app.canvas.graph.add(node); + + // Wait for widgets to be created + await new Promise(resolve => setTimeout(resolve, 50)); + + // Find the image combo widget and set it to our uploaded filename + const imageWidget = node.widgets.find(w => w.name === 'image'); + if (imageWidget) { + imageWidget.value = filename; + // Trigger value change to update the node display + if (imageWidget.callback) { + imageWidget.callback(filename); + } + } + + // Select the new node + app.canvas.selectNodes([node]); + + return node; + }; + + /** + * Load an image file into a LoadImage node by updating its widget + */ + const loadImageIntoNode = async (node, file) => { + // Upload the image first + const filename = await uploadImageFile(file); + if (!filename) { + console.error('[PowerLoadVideo] Failed to upload image!'); + return false; + } + + // Find the image combo widget and set it to our uploaded filename + const imageWidget = node.widgets.find(w => w.name === 'image'); + if (imageWidget) { + imageWidget.value = filename; + // Trigger value change to update the node display + if (imageWidget.callback) { + imageWidget.callback(filename); + } + return true; + } + return false; + }; + + /** + * Check if a file is an image type + */ + const isImageFile = (file) => { + return file.type.startsWith('image/') || + file.name.toLowerCase().match(/\.(png|jpg|jpeg|gif|webp|bmp)$/i); + }; + + /** + * Check if a point is inside a node's bounding box + */ + const isPointInNode = (pointX, pointY, node) => { + // Node position and size in graph coordinates + const nodeLeft = node.pos[0]; + const nodeTop = node.pos[1]; + const nodeRight = nodeLeft + node.size[0]; + const nodeBottom = nodeTop + node.size[1]; + + return pointX >= nodeLeft && pointX <= nodeRight && + pointY >= nodeTop && pointY <= nodeBottom; + }; + + /** + * Check if the drop target is over a LoadImage node + */ + const getLoadImageNodeAtPosition = (clientX, clientY) => { + // Get canvas rect for coordinate conversion + const rect = canvas.getBoundingClientRect(); + const mouseX = clientX - rect.left; + const mouseY = clientY - rect.top; + + // Convert to graph coordinates + const ds = app.canvas.ds || { scale: 1, offset: [0, 0] }; + const graphX = mouseX / ds.scale - ds.offset[0]; + const graphY = mouseY / ds.scale - ds.offset[1]; + + // Find all LoadImage nodes and check if mouse is over any of them + const loadImageNodes = app.canvas.graph.nodes.filter( + node => node.type === 'LoadImage' + ); + + for (const node of loadImageNodes) { + if (isPointInNode(graphX, graphY, node)) { + return node; + } + } + return null; + }; + const handleDrop = async (e) => { e.preventDefault(); e.stopPropagation(); @@ -143,6 +277,16 @@ app.registerExtension({ return; } + // Check if dropping over a LoadImage node (for any image type) + if (isImageFile(file)) { + const loadImageNode = getLoadImageNodeAtPosition(e.clientX, e.clientY); + if (loadImageNode) { + // Drop onto existing LoadImage node - load image into it + await loadImageIntoNode(loadImageNode, file); + return; + } + } + // Check if it's a PNG image with embedded workflow if (file.type === 'image/png') { try { @@ -158,6 +302,39 @@ app.registerExtension({ } } + // If it's an image file without embedded workflow, create LoadImage node + if (isImageFile(file)) { + isHandlingDrop = true; + droppedFile = file; + + try { + // Upload the image file + const filename = await uploadImageFile(file); + + if (filename) { + // Wait a moment for node types to be registered + await new Promise(resolve => setTimeout(resolve, 100)); + + // Calculate mouse position in graph coordinates + const ds = app.canvas.ds || { scale: 1, offset: [0, 0] }; + const rect = canvas.getBoundingClientRect(); + const mouseX = e.clientX - rect.left; + const mouseY = e.clientY - rect.top; + const graphX = mouseX / ds.scale - ds.offset[0]; + const graphY = mouseY / ds.scale - ds.offset[1]; + + // Create LoadImage node at drop position + await createLoadImageNodeWithImage(filename, [graphX, graphY]); + } else { + console.error('[PowerLoadVideo] Image upload failed!'); + } + } finally { + isHandlingDrop = false; + droppedFile = null; + } + return; + } + // Check if it's a video file if (!file.type.startsWith('video/')) { return;