import { app } from "../../../scripts/app.js"; import { api } from "../../../scripts/api.js"; let loopEnabled = false; app.registerExtension({ name: "AudioCraft.AudioManager", async beforeRegisterNodeDef(nodeType, nodeData, app) { if (nodeData.name === "AudioManager") { const onExecuted = nodeType.prototype.onExecuted; nodeType.prototype.onExecuted = function (message) { onExecuted?.apply(this, arguments); if (!message?.text) return; const summary = message.text[0]?.content || ""; const files = message.files || []; if (this._managerWidget) { this._managerContainer.innerHTML = ""; buildContent(this._managerContainer, summary, files); } else { const container = document.createElement("div"); container.style.cssText = "padding:4px;overflow-y:auto;"; buildContent(container, summary, files); this._managerContainer = container; this._managerWidget = this.addDOMWidget("audio_manager", "dom", container, { serialize: false, hideOnZoom: false, }); } const listHeight = Math.min(40 + files.length * 26, 800); this._managerWidget.computeSize = () => [this.size[0], listHeight]; this.setSize([Math.max(this.size[0], 500), listHeight + 80]); app.graph.setDirtyCanvas(true); }; } }, }); // Track currently playing audio globally so only one plays at a time 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; } } function buildContent(container, summary, files) { // Header with summary + loop toggle 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;"; const headerText = document.createElement("span"); headerText.textContent = summary; headerText.style.cssText = "font-weight:bold;color:#fff;font-size:13px;"; const loopBtn = document.createElement("button"); loopBtn.textContent = loopEnabled ? "\uD83D\uDD01 Loop AN" : "\uD83D\uDD01 Loop AUS"; loopBtn.style.cssText = `background:${loopEnabled ? "#2a5a2a" : "#444"};border:none;color:${loopEnabled ? "#8f8" : "#888"};cursor:pointer;padding:3px 8px;border-radius:3px;font-size:11px;`; loopBtn.onclick = () => { loopEnabled = !loopEnabled; loopBtn.textContent = loopEnabled ? "\uD83D\uDD01 Loop AN" : "\uD83D\uDD01 Loop AUS"; loopBtn.style.background = loopEnabled ? "#2a5a2a" : "#444"; loopBtn.style.color = loopEnabled ? "#8f8" : "#888"; if (activeAudio) { activeAudio.loop = loopEnabled; } }; headerRow.appendChild(headerText); headerRow.appendChild(loopBtn); 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;"; playBtn.onclick = () => { // If clicking the same button that's playing, stop it if (activeBtn === playBtn) { stopActive(); return; } // Stop any other playing audio first 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; } }; }; 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 () => { // Stop if this file is playing 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); } }; row.appendChild(name); row.appendChild(size); row.appendChild(playBtn); row.appendChild(dlBtn); row.appendChild(delBtn); container.appendChild(row); } }