|
1112 | 1112 | found = true; |
1113 | 1113 | BACKEND = testUrl; |
1114 | 1114 | connected = true; |
| 1115 | + if (data.csrf_token) csrfToken = data.csrf_token; |
1115 | 1116 | el.connDot.className = "conn-dot on"; |
1116 | 1117 | el.connLabel.textContent = "Connected" + (port !== BACKEND_BASE_PORT ? " (:" + port + ")" : ""); |
1117 | 1118 | el.backendPort.textContent = "Port " + port; |
1118 | 1119 | if (data.capabilities) capabilities = data.capabilities; |
| 1120 | + healthBackoff = HEALTH_MS; |
| 1121 | + clearInterval(healthTimer); |
| 1122 | + healthTimer = setInterval(checkHealth, HEALTH_MS); |
1119 | 1123 | updateButtons(); |
1120 | 1124 | loadCapabilities(); |
1121 | 1125 | portScanPending = false; |
|
3332 | 3336 | api("POST", "/whisper/clear-cache", {}, function (err, data) { |
3333 | 3337 | if (!err && data) { |
3334 | 3338 | if (data.success) { |
3335 | | - showAlert("Cache cleared! Cleared " + data.cleared.length + " location(s). Models will re-download on next use."); |
| 3339 | + showAlert("Cache cleared! Cleared " + (data.cleared ? data.cleared.length : 0) + " location(s). Models will re-download on next use."); |
3336 | 3340 | } else { |
3337 | 3341 | showAlert("Cache clear had errors: " + (data.errors ? data.errors.join(", ") : "unknown")); |
3338 | 3342 | } |
|
4608 | 4612 |
|
4609 | 4613 | function refreshOutputs() { |
4610 | 4614 | api("GET", "/outputs/recent", null, function (err, data) { |
4611 | | - if (err || !data) return; |
| 4615 | + if (err || !data || !Array.isArray(data)) return; |
4612 | 4616 | if (el.outputBrowserToggle) { |
4613 | 4617 | el.outputBrowserToggle.textContent = "Outputs (" + data.length + ")"; |
4614 | 4618 | } |
|
5004 | 5008 | return; |
5005 | 5009 | } |
5006 | 5010 | el.clipPreviewRow.classList.remove("hidden"); |
5007 | | - el.clipThumb.innerHTML = '<div class="clip-thumb-loading"></div>'; |
5008 | | - el.clipMetaRes.textContent = ""; |
5009 | | - el.clipMetaDur.textContent = ""; |
5010 | | - el.clipMetaSize.textContent = ""; |
| 5011 | + if (el.clipThumb) el.clipThumb.innerHTML = '<div class="clip-thumb-loading"></div>'; |
| 5012 | + if (el.clipMetaRes) el.clipMetaRes.textContent = ""; |
| 5013 | + if (el.clipMetaDur) el.clipMetaDur.textContent = ""; |
| 5014 | + if (el.clipMetaSize) el.clipMetaSize.textContent = ""; |
5011 | 5015 | // Fetch thumbnail |
5012 | 5016 | api("POST", "/video/preview-frame", { file: selectedPath, timestamp: "00:00:01", width: 160 }, function(err, data) { |
5013 | 5017 | if (err || !data || !data.image) { |
5014 | | - el.clipThumb.innerHTML = '<div class="clip-thumb-none">No Preview</div>'; |
| 5018 | + if (el.clipThumb) el.clipThumb.innerHTML = '<div class="clip-thumb-none">No Preview</div>'; |
5015 | 5019 | return; |
5016 | 5020 | } |
5017 | | - el.clipThumb.innerHTML = '<img src="data:image/jpeg;base64,' + data.image + '" alt="preview">'; |
| 5021 | + if (el.clipThumb) el.clipThumb.innerHTML = '<img src="data:image/jpeg;base64,' + data.image + '" alt="preview">'; |
5018 | 5022 | }); |
5019 | 5023 | // Fetch metadata via probe |
5020 | 5024 | api("POST", "/audio/waveform", { file: selectedPath, samples: 1 }, function(err, data) { |
5021 | 5025 | if (!err && data && data.duration) { |
5022 | 5026 | var dur = Math.round(data.duration); |
5023 | 5027 | var m = Math.floor(dur / 60); |
5024 | 5028 | var s = dur % 60; |
5025 | | - el.clipMetaDur.textContent = m + ":" + (s < 10 ? "0" : "") + s; |
| 5029 | + if (el.clipMetaDur) el.clipMetaDur.textContent = m + ":" + (s < 10 ? "0" : "") + s; |
5026 | 5030 | } |
5027 | 5031 | }); |
5028 | 5032 | } |
|
5106 | 5110 | var _paletteResults = []; |
5107 | 5111 |
|
5108 | 5112 | function openCommandPalette() { |
5109 | | - if (!el.commandPaletteOverlay) return; |
| 5113 | + if (!el.commandPaletteOverlay || !el.commandPaletteInput || !el.commandPaletteResults) return; |
5110 | 5114 | el.commandPaletteOverlay.classList.remove("hidden"); |
5111 | 5115 | el.commandPaletteInput.value = ""; |
5112 | 5116 | renderPaletteResults(""); |
5113 | | - setTimeout(function() { el.commandPaletteInput.focus(); }, 50); |
| 5117 | + setTimeout(function() { if (el.commandPaletteInput) el.commandPaletteInput.focus(); }, 50); |
5114 | 5118 | } |
5115 | 5119 |
|
5116 | 5120 | function closeCommandPalette() { |
|
5134 | 5138 | if (_paletteResults.length === 0) { |
5135 | 5139 | html = '<div class="command-palette-empty">No matching operations</div>'; |
5136 | 5140 | } |
5137 | | - el.commandPaletteResults.innerHTML = html; |
| 5141 | + if (el.commandPaletteResults) el.commandPaletteResults.innerHTML = html; |
5138 | 5142 | } |
5139 | 5143 |
|
5140 | 5144 | function executePaletteItem(tab, sub) { |
|
5143 | 5147 | } |
5144 | 5148 |
|
5145 | 5149 | function paletteNavigate(dir) { |
5146 | | - if (!_paletteResults.length) return; |
| 5150 | + if (!_paletteResults.length || !el.commandPaletteResults) return; |
5147 | 5151 | var items = el.commandPaletteResults.querySelectorAll(".command-palette-item"); |
5148 | 5152 | if (items[_paletteSelectedIdx]) items[_paletteSelectedIdx].classList.remove("selected"); |
5149 | 5153 | _paletteSelectedIdx += dir; |
|
5163 | 5167 | } |
5164 | 5168 |
|
5165 | 5169 | function initCommandPalette() { |
5166 | | - if (!el.commandPaletteOverlay) return; |
| 5170 | + if (!el.commandPaletteOverlay || !el.commandPaletteInput || !el.commandPaletteResults) return; |
5167 | 5171 |
|
5168 | 5172 | el.commandPaletteInput.addEventListener("input", function() { |
5169 | 5173 | renderPaletteResults(this.value); |
|
5727 | 5731 |
|
5728 | 5732 | // v1.3.0 - Recent Clips |
5729 | 5733 | if (el.recentClipsBtn) el.recentClipsBtn.addEventListener("click", showRecentClips); |
| 5734 | + // Close recent clips dropdown on outside click |
| 5735 | + document.addEventListener("click", function(e) { |
| 5736 | + if (el.recentClipsDropdown && !el.recentClipsDropdown.classList.contains("hidden") && |
| 5737 | + !e.target.closest("#recentClipsBtn") && !e.target.closest("#recentClipsDropdown")) { |
| 5738 | + el.recentClipsDropdown.classList.add("hidden"); |
| 5739 | + } |
| 5740 | + }); |
5730 | 5741 | if (el.recentClipsDropdown) el.recentClipsDropdown.addEventListener("click", function(e) { |
5731 | 5742 | var item = e.target.closest(".recent-clip-item"); |
5732 | 5743 | if (item) { |
|
0 commit comments