|
| 1 | +// ComfyUI-BerniniR — preview + carga de vídeo para "BerniniR · Load Video". |
| 2 | +// Añade un botón que acepta mp4/mov/avi/mkv/webm/webp/gif (el uploader de |
| 3 | +// imágenes de ComfyUI no deja elegir vídeo) y un preview para ver que cargó. |
| 4 | +import { app } from "../../scripts/app.js"; |
| 5 | +import { api } from "../../scripts/api.js"; |
| 6 | + |
| 7 | +const ANIM = ["webp", "gif"]; |
| 8 | + |
| 9 | +function viewURL(name) { |
| 10 | + return api.apiURL(`/view?filename=${encodeURIComponent(name)}&type=input&subfolder=`); |
| 11 | +} |
| 12 | + |
| 13 | +app.registerExtension({ |
| 14 | + name: "BerniniR.LoadVideoPreview", |
| 15 | + async beforeRegisterNodeDef(nodeType, nodeData) { |
| 16 | + if (nodeData?.name !== "BerniniRLoadVideo") return; |
| 17 | + |
| 18 | + const onCreated = nodeType.prototype.onNodeCreated; |
| 19 | + nodeType.prototype.onNodeCreated = function () { |
| 20 | + const ret = onCreated?.apply(this, arguments); |
| 21 | + const node = this; |
| 22 | + |
| 23 | + // --- preview --- |
| 24 | + const wrap = document.createElement("div"); |
| 25 | + wrap.style.cssText = "width:100%;display:flex;justify-content:center;align-items:center;"; |
| 26 | + const video = document.createElement("video"); |
| 27 | + video.controls = true; video.loop = true; video.muted = true; video.playsInline = true; |
| 28 | + video.style.cssText = "max-width:100%;max-height:240px;border-radius:8px;display:none;"; |
| 29 | + const img = document.createElement("img"); |
| 30 | + img.style.cssText = "max-width:100%;max-height:240px;border-radius:8px;display:none;"; |
| 31 | + wrap.appendChild(video); wrap.appendChild(img); |
| 32 | + node.addDOMWidget("br_preview", "preview", wrap, { serialize: false }); |
| 33 | + |
| 34 | + const show = (name) => { |
| 35 | + const empty = !name || name === "source.webp"; |
| 36 | + const ext = empty ? "" : (name.split(".").pop() || "").toLowerCase(); |
| 37 | + if (empty) { |
| 38 | + video.style.display = "none"; img.style.display = "none"; video.removeAttribute("src"); |
| 39 | + } else if (ANIM.includes(ext)) { |
| 40 | + img.src = viewURL(name); img.style.display = "block"; |
| 41 | + video.style.display = "none"; video.removeAttribute("src"); |
| 42 | + } else { |
| 43 | + video.src = viewURL(name); video.style.display = "block"; |
| 44 | + img.style.display = "none"; video.load(); |
| 45 | + } |
| 46 | + node.setDirtyCanvas?.(true, true); |
| 47 | + }; |
| 48 | + |
| 49 | + const combo = node.widgets?.find((w) => w.name === "video"); |
| 50 | + if (combo) { |
| 51 | + const prev = combo.callback; |
| 52 | + combo.callback = function () { |
| 53 | + const r = prev?.apply(this, arguments); |
| 54 | + show(combo.value); |
| 55 | + return r; |
| 56 | + }; |
| 57 | + setTimeout(() => show(combo.value), 100); |
| 58 | + } |
| 59 | + |
| 60 | + // --- botón de carga (acepta vídeo, no solo imagen) --- |
| 61 | + const picker = document.createElement("input"); |
| 62 | + picker.type = "file"; |
| 63 | + picker.accept = "video/*,image/webp,image/gif"; |
| 64 | + picker.style.display = "none"; |
| 65 | + document.body.appendChild(picker); |
| 66 | + picker.onchange = async () => { |
| 67 | + const file = picker.files?.[0]; |
| 68 | + picker.value = ""; |
| 69 | + if (!file) return; |
| 70 | + const body = new FormData(); |
| 71 | + body.append("image", file); |
| 72 | + body.append("type", "input"); |
| 73 | + body.append("subfolder", ""); |
| 74 | + try { |
| 75 | + const resp = await api.fetchApi("/upload/image", { method: "POST", body }); |
| 76 | + if (resp.status !== 200) throw new Error(await resp.text()); |
| 77 | + const data = await resp.json(); |
| 78 | + const name = data.subfolder ? `${data.subfolder}/${data.name}` : data.name; |
| 79 | + if (combo) { |
| 80 | + const vals = combo.options?.values; |
| 81 | + if (Array.isArray(vals) && !vals.includes(name)) vals.push(name); |
| 82 | + combo.value = name; |
| 83 | + combo.callback?.(name); |
| 84 | + } |
| 85 | + } catch (e) { |
| 86 | + alert("BerniniR: fallo al cargar el vídeo -> " + e); |
| 87 | + } |
| 88 | + }; |
| 89 | + node.addWidget("button", "📹 Cargar vídeo (mp4 / webp / gif)", null, () => picker.click()); |
| 90 | + |
| 91 | + return ret; |
| 92 | + }; |
| 93 | + }, |
| 94 | +}); |
0 commit comments