import { invoke } from "@tauri-apps/api/core"; const startAudioBtn = document.querySelector("#start-audio-btn"); const stopAudioBtn = document.querySelector("#stop-audio-btn"); const audioStatus = document.querySelector("#audio-status"); const startVideoBtn = document.querySelector("#start-video-btn"); const stopVideoBtn = document.querySelector("#stop-video-btn"); const videoStatus = document.querySelector("#video-status"); const videoPreview = document.querySelector("#video-preview"); if ( startAudioBtn === null || stopAudioBtn === null || audioStatus === null || startVideoBtn === null || stopVideoBtn === null || videoStatus === null || videoPreview === null ) { throw new Error("missing UI elements"); } let previewTimer: number | null = null; let previewRequestInFlight = false; function setAudioStatus(message: string): void { if (audioStatus) audioStatus.textContent = message; } function setAudioButtons(isRecording: boolean): void { if (startAudioBtn) startAudioBtn.disabled = isRecording; if (stopAudioBtn) stopAudioBtn.disabled = !isRecording; } function setVideoStatus(message: string): void { if (videoStatus) videoStatus.textContent = message; } function setVideoButtons(isRecording: boolean): void { if (startVideoBtn) startVideoBtn.disabled = isRecording; if (stopVideoBtn) stopVideoBtn.disabled = !isRecording; } async function refreshPreviewFrame(): Promise { if (previewRequestInFlight) { return; } previewRequestInFlight = true; try { const encoded = await invoke("get_video_preview_frame_base64"); if (encoded !== null && encoded.length > 0) { updatePreviewImageFromBase64(encoded); } } catch (error) { console.error("preview refresh failed", error); } finally { previewRequestInFlight = false; } } function startPreviewPolling(): void { if (previewTimer !== null) { return; } console.log("starting preview polling"); window.setTimeout(() => { void refreshPreviewFrame(); }, 120); previewTimer = window.setInterval(() => { void refreshPreviewFrame(); }, 200); } function stopPreviewPolling(): void { if (previewTimer !== null) { window.clearInterval(previewTimer); previewTimer = null; } previewRequestInFlight = false; if (videoPreview) videoPreview.removeAttribute("src"); if (previewObjectUrl !== null) { URL.revokeObjectURL(previewObjectUrl); previewObjectUrl = null; } } startAudioBtn.addEventListener("click", async () => { startAudioBtn.disabled = true; try { const path = await invoke("start_audio_recording"); setAudioStatus(`Audio recording started.\nOutput: ${path}`); setAudioButtons(true); } catch (error) { setAudioStatus(`Start audio failed.\n${String(error)}`); setAudioButtons(false); } }); stopAudioBtn.addEventListener("click", async () => { stopAudioBtn.disabled = true; try { const path = await invoke("stop_audio_recording"); setAudioStatus(`Audio recording stopped.\nSaved file: ${path}`); setAudioButtons(false); } catch (error) { setAudioStatus(`Stop audio failed.\n${String(error)}`); setAudioButtons(true); } }); startVideoBtn.addEventListener("click", async () => { startVideoBtn.disabled = true; try { const path = await invoke("start_video_recording"); setVideoStatus(`Video recording started.\nOutput: ${path}`); setVideoButtons(true); startPreviewPolling(); } catch (error) { setVideoStatus(`Start video failed.\n${String(error)}`); setVideoButtons(false); stopPreviewPolling(); } }); stopVideoBtn.addEventListener("click", async () => { stopVideoBtn.disabled = true; try { const path = await invoke("stop_video_recording"); setVideoStatus(`Video recording stopped.\nSaved file: ${path}`); setVideoButtons(false); stopPreviewPolling(); } catch (error) { setVideoStatus(`Stop video failed.\n${String(error)}`); setVideoButtons(true); } }); let previewObjectUrl: string | null = null; function base64ToUint8Array(base64: string): Uint8Array { const binary = window.atob(base64); const bytes = new Uint8Array(binary.length); for (let index = 0;index < binary.length;index += 1) { bytes[index] = binary.charCodeAt(index); } return bytes; } function updatePreviewImageFromBase64(encoded: string): void { const bytes = base64ToUint8Array(encoded); const copied = new Uint8Array(bytes.byteLength); copied.set(bytes); const blob = new Blob([copied.buffer], { type: "image/jpeg" }); const objectUrl = URL.createObjectURL(blob); if (previewObjectUrl !== null) { URL.revokeObjectURL(previewObjectUrl); } previewObjectUrl = objectUrl; if (videoPreview) videoPreview.src = objectUrl; }