diff --git a/web/app.js b/web/app.js index 7d809c9..6a04acb 100644 --- a/web/app.js +++ b/web/app.js @@ -38,8 +38,10 @@ const gpuToggle = qs('gpuToggle'); const signalList = qs('signalList'); const eventList = qs('eventList'); +const recordingList = qs('recordingList'); const signalCountBadge = qs('signalCountBadge'); const eventCountBadge = qs('eventCountBadge'); +const recordingCountBadge = qs('recordingCountBadge'); const healthBuffer = qs('healthBuffer'); const healthDropped = qs('healthDropped'); @@ -112,6 +114,8 @@ let lastEventEndMs = 0; let selectedEventId = null; let timelineRects = []; let liveSignalRects = []; +let recordings = []; +let recordingsFetchInFlight = false; const GAIN_MAX = 60; const timelineWindowMs = 5 * 60 * 1000; @@ -761,6 +765,26 @@ function renderLists() { `).join(''); } + + if (recordingList && recordingCountBadge) { + recordingCountBadge.textContent = `${recordings.length}`; + if (recordings.length === 0) { + recordingList.innerHTML = '
No recordings yet.
'; + } else { + recordingList.innerHTML = recordings.slice(0, 50).map((rec) => ` + + `).join(''); + } + } } function normalizeEvent(ev) { @@ -811,6 +835,22 @@ async function fetchEvents(initial) { } } +async function fetchRecordings() { + if (recordingsFetchInFlight || !recordingList) return; + recordingsFetchInFlight = true; + try { + const res = await fetch('/api/recordings'); + if (!res.ok) return; + const data = await res.json(); + if (Array.isArray(data)) { + recordings = data; + renderLists(); + } + } finally { + recordingsFetchInFlight = false; + } +} + function openDrawer(ev) { if (!ev) return; selectedEventId = ev.id; @@ -1127,6 +1167,16 @@ eventList.addEventListener('click', (ev) => { openDrawer(eventsById.get(id)); }); +if (recordingList) { + recordingList.addEventListener('click', async (ev) => { + const target = ev.target.closest('.recording-item'); + if (!target) return; + const id = target.dataset.id; + const audio = new Audio(`/api/recordings/${id}/audio`); + audio.play(); + }); +} + window.addEventListener('keydown', (ev) => { if (ev.target && ['INPUT', 'SELECT', 'TEXTAREA'].includes(ev.target.tagName)) return; if (ev.key === ' ') { @@ -1159,8 +1209,10 @@ loadConfig(); loadStats(); loadGPU(); fetchEvents(true); +fetchRecordings(); connect(); requestAnimationFrame(renderLoop); setInterval(loadStats, 1000); setInterval(loadGPU, 1000); setInterval(() => fetchEvents(false), 2000); +setInterval(fetchRecordings, 5000); diff --git a/web/index.html b/web/index.html index d7a0e8d..ad08357 100644 --- a/web/index.html +++ b/web/index.html @@ -104,6 +104,7 @@ +
@@ -198,6 +199,11 @@
Render rate-
+ +
+
Recordings0
+
No recordings yet.
+