Download web/ogg_editor.js from supermind/OGG-Comfy: direct link, hf CLI and curl.
- Browser
- Download file 4.15 kB
-
https://huggingface.co/supermind/OGG-Comfy/resolve/main/web/ogg_editor.js
- Command line
-
hf download hf://supermind/OGG-Comfy/web/ogg_editor.js
-
curl -L -o ogg_editor.js https://huggingface.co/supermind/OGG-Comfy/resolve/main/web/ogg_editor.js
4.15 kB
| // The OGG Editor node: the editor core (editor_core.js) on a ComfyUI node. The node keeps the editor's settings | |
| // and edits in its hidden "edits" widget and the names of its last take's preview files in its properties; the server | |
| // plans edits at /ogg/editor/plan, and "Use these edits" queues the workflow, which renders the same plan. | |
| import { EditorView, EditorWindow, TakePreview, injectStyle, loadTake } from "./editor_core.js"; | |
| const { app } = window.comfyAPI.app; | |
| const { api } = window.comfyAPI.api; | |
| function viewUrl(name, subfolder, type) { | |
| return api.apiURL(`/view?${new URLSearchParams({ filename: name, subfolder, type })}`); | |
| } | |
| function hideWidget(w) { | |
| if (!w) return; | |
| w.hidden = true; | |
| w.computeSize = () => [0, -4]; | |
| } | |
| async function requestPlan(analysis, edits) { | |
| const response = await api.fetchApi("/ogg/editor/plan", { | |
| method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ analysis, edits }), | |
| }); | |
| if (!response.ok) throw new Error(`plan: HTTP ${response.status}`); | |
| return response.json(); | |
| } | |
| app.registerExtension({ | |
| name: "Ogg.Editor", | |
| async beforeRegisterNodeDef(nodeType, nodeData) { | |
| if (nodeData.name !== "OggEditor") return; | |
| injectStyle(); | |
| const onNodeCreated = nodeType.prototype.onNodeCreated; | |
| nodeType.prototype.onNodeCreated = function () { | |
| const r = onNodeCreated?.apply(this, arguments); | |
| const node = this; | |
| const editsW = this.widgets?.find((w) => w.name === "edits"); | |
| hideWidget(editsW); | |
| const readEdits = () => { try { return JSON.parse(editsW?.value || "{}"); } catch { return {}; } }; | |
| const writeEdits = (edits) => { | |
| if (!editsW) return; | |
| editsW.value = JSON.stringify(edits); | |
| editsW.callback?.(editsW.value); | |
| node.setDirtyCanvas?.(true, true); | |
| }; | |
| const view = new EditorView({ readEdits, writeEdits, apply: () => app.queuePrompt(0, 1), plan: requestPlan }); | |
| this.oggView = view; | |
| let window_ = null; | |
| const preview = new TakePreview(view, { | |
| emptyText: "Run the workflow to hear, read and edit the take here.", | |
| onOpen: () => { if (!window_) window_ = new EditorWindow(view, () => { window_ = null; view.emit(); }); }, | |
| }); | |
| for (const type of ["pointerdown", "wheel"]) preview.root.addEventListener(type, (e) => e.stopPropagation()); | |
| const widget = this.addDOMWidget("ogg_editor", "div", preview.root, { serialize: false, getMinHeight: () => 190 }); | |
| widget.serialize = false; | |
| if (!this.size || this.size[0] < 420 || this.size[1] < 300) this.setSize([Math.max(this.size?.[0] ?? 0, 460), Math.max(this.size?.[1] ?? 0, 320)]); | |
| let loaded = null; | |
| const load = async (entry) => { | |
| if (loaded === entry.audio + entry.analysis) { await view.replan(); return; } | |
| preview.setStatus("Loading the take..."); | |
| try { | |
| await loadTake(view, viewUrl(entry.analysis, entry.subfolder, entry.type), viewUrl(entry.audio, entry.subfolder, entry.type)); | |
| loaded = entry.audio + entry.analysis; | |
| preview.setStatus(null); | |
| window_?.renderAll(); | |
| } catch (err) { | |
| preview.setStatus("The take's preview is gone (ComfyUI empties its temp folder on restart). Run the workflow again."); | |
| console.warn("OGG Editor:", err); | |
| } | |
| }; | |
| const onExecuted = this.onExecuted; | |
| this.onExecuted = function (output) { | |
| onExecuted?.apply(this, arguments); | |
| const entry = output?.ogg_editor?.[0]; | |
| if (!entry) return; | |
| this.properties = this.properties || {}; | |
| this.properties.ogg_editor = entry; | |
| load(entry); | |
| }; | |
| const onConfigure = this.onConfigure; | |
| this.onConfigure = function () { | |
| onConfigure?.apply(this, arguments); | |
| hideWidget(editsW); | |
| const entry = this.properties?.ogg_editor; | |
| if (entry) load(entry); | |
| }; | |
| const onRemoved = this.onRemoved; | |
| this.onRemoved = function () { | |
| onRemoved?.apply(this, arguments); | |
| window_?.close(); | |
| view.destroy(); | |
| }; | |
| return r; | |
| }; | |
| }, | |
| }); | |