import { app } from "../../../scripts/app.js"; import { api } from "../../../scripts/api.js"; let loopEnabled = false; let activeAudio = null; let activeBtn = null; function stopActive() { if (activeAudio) { activeAudio.pause(); activeAudio = null; } if (activeBtn) { activeBtn.textContent = "\u25B6"; activeBtn.style.color = "#8f8"; activeBtn = null; } } async function refreshFileList(node) { try { const resp = await api.fetchApi("/audiocraft/list"); const data = await resp.json(); const container = node._managerContainer; container.innerHTML = ""; buildContent(container, data.summary, data.files); const listHeight = Math.min(40 + data.files.length * 26, 800); node._managerWidget.computeSize = () => [node.size[0], listHeight]; node.setSize([Math.max(node.size[0], 500), listHeight + 80]); app.graph.setDirtyCanvas(true); } catch (e) { console.error("Refresh failed:", e); } } app.registerExtension({ name: "AudioCraft.AudioManager", async beforeRegisterNodeDef(nodeType, nodeData, app) { if (nodeData.name === "AudioManager") { const origOnNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = function () { origOnNodeCreated?.apply(this, arguments); const container = document.createElement("div"); container.style.cssText = "padding:4px;overflow-y:auto;"; const loadingMsg = document.createElement("div"); loadingMsg.textContent = "Klicke \u21BB Refresh um Dateien zu laden"; loadingMsg.style.cssText = "color:#888;font-size:12px;padding:8px;"; container.appendChild(loadingMsg); this._managerContainer = container; this._managerWidget = this.addDOMWidget("audio_manager", "dom", container, { serialize: false, hideOnZoom: false, }); this._managerWidget.computeSize = () => [this.size[0], 60]; // Auto-refresh on creation setTimeout(() => refreshFileList(this), 500); }; // Also refresh when node is executed via Queue const onExecuted = nodeType.prototype.onExecuted; nodeType.prototype.onExecuted = function (message) { onExecuted?.apply(this, arguments); refreshFileList(this); }; } }, }); // Listen for any prompt execution to auto-refresh AudioManager nodes api.addEventListener("executed", (event) => { // After any node executes, refresh all AudioManager nodes if (event?.detail?.node) { const nodes = app.graph._nodes.filter(n => n.type === "AudioManager"); for (const node of nodes) { if (node._managerContainer) { refreshFileList(node); } } } }); function buildContent(container, summary, files) { const headerRow = document.createElement("div"); headerRow.style.cssText = "display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;padding:4px;background:#333;border-radius:4px;gap:4px;"; const headerText = document.createElement("span"); headerText.textContent = summary; headerText.style.cssText = "font-weight:bold;color:#fff;font-size:12px;white-space:nowrap;"; const btnGroup = document.createElement("div"); btnGroup.style.cssText = "display:flex;gap:4px;"; const refreshBtn = document.createElement("button"); refreshBtn.textContent = "\u21BB Refresh"; refreshBtn.style.cssText = "background:#2a3a5a;border:none;color:#8cf;cursor:pointer;padding:3px 8px;border-radius:3px;font-size:11px;white-space:nowrap;"; refreshBtn.onclick = () => { const node = app.graph._nodes.find(n => n._managerContainer === container.parentElement || n._managerContainer === container); if (node) refreshFileList(node); }; const loopBtn = document.createElement("button"); loopBtn.textContent = loopEnabled ? "\uD83D\uDD01 Loop AN" : "\uD83D\uDD01 Loop"; loopBtn.style.cssText = `background:${loopEnabled ? "#2a5a2a" : "#444"};border:none;color:${loopEnabled ? "#8f8" : "#888"};cursor:pointer;padding:3px 8px;border-radius:3px;font-size:11px;white-space:nowrap;`; loopBtn.onclick = () => { loopEnabled = !loopEnabled; loopBtn.textContent = loopEnabled ? "\uD83D\uDD01 Loop AN" : "\uD83D\uDD01 Loop"; loopBtn.style.background = loopEnabled ? "#2a5a2a" : "#444"; loopBtn.style.color = loopEnabled ? "#8f8" : "#888"; if (activeAudio) activeAudio.loop = loopEnabled; }; btnGroup.appendChild(refreshBtn); btnGroup.appendChild(loopBtn); headerRow.appendChild(headerText); headerRow.appendChild(btnGroup); container.appendChild(headerRow); if (files.length === 0) return; for (const f of files) { const row = document.createElement("div"); row.style.cssText = "display:flex;align-items:center;padding:3px 2px;font-size:11px;color:#ccc;border-bottom:1px solid #333;min-height:22px;"; const name = document.createElement("span"); name.textContent = f.name; name.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;margin-right:6px;"; const size = document.createElement("span"); size.textContent = f.size_mb + " MB"; size.style.cssText = "color:#8cf;min-width:55px;text-align:right;margin-right:6px;font-size:10px;"; const playBtn = document.createElement("button"); playBtn.textContent = "\u25B6"; playBtn.title = "Abspielen"; playBtn.style.cssText = "background:#444;border:none;color:#8f8;cursor:pointer;padding:2px 8px;border-radius:3px;font-size:11px;margin-right:4px;"; const audioSrc = api.apiURL( `/view?filename=${encodeURIComponent(f.name)}&subfolder=audio&type=output` ); const dlBtn = document.createElement("a"); dlBtn.href = audioSrc; dlBtn.download = f.name; dlBtn.textContent = "\u2B07"; dlBtn.title = "Download"; dlBtn.style.cssText = "color:#8cf;text-decoration:none;font-size:13px;padding:0 4px;"; const delBtn = document.createElement("button"); delBtn.textContent = "\u2716"; delBtn.title = "Loeschen"; delBtn.style.cssText = "background:#533;border:none;color:#f66;cursor:pointer;padding:2px 6px;border-radius:3px;font-size:11px;margin-left:4px;"; delBtn.onclick = async () => { if (activeBtn === playBtn) stopActive(); try { const resp = await api.fetchApi("/audiocraft/delete", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({filename: f.name}), }); if (resp.ok) { row.style.opacity = "0.3"; row.style.pointerEvents = "none"; delBtn.textContent = "\u2714"; delBtn.style.color = "#888"; } } catch (e) { console.error("Delete failed:", e); } }; playBtn.onclick = () => { if (activeBtn === playBtn) { stopActive(); return; } stopActive(); const audio = new Audio(audioSrc); audio.loop = loopEnabled; audio.play(); activeAudio = audio; activeBtn = playBtn; playBtn.textContent = "\u25A0"; playBtn.style.color = "#f88"; audio.onended = () => { if (!audio.loop) { playBtn.textContent = "\u25B6"; playBtn.style.color = "#8f8"; activeAudio = null; activeBtn = null; } }; }; row.appendChild(name); row.appendChild(size); row.appendChild(playBtn); row.appendChild(dlBtn); row.appendChild(delBtn); container.appendChild(row); } }