Instead of chmod on every app start, catch EACCES (error 13) when
spawning sidecar or ffmpeg, fix permissions, then retry once:
- sidecar spawn: catches permission denied, runs set_executable_permissions
on the sidecar dir, retries spawn
- ffmpeg: catches permission denied, chmod +x ffmpeg and ffprobe, retries
Zero overhead on normal launches. Only fixes permissions when actually needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The chmod fix only ran after fresh extraction, but existing sidecar
dirs extracted by older versions still lacked execute permissions.
Now set_executable_permissions() runs on EVERY app launch (both the
early-return path for existing dirs and after fresh extraction).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously only the main sidecar binary got chmod 755. Now all files
in the extraction directory get execute permissions — covers ffmpeg,
ffprobe, and any other bundled binaries. Applied in three places:
- sidecar/mod.rs: after local extraction
- commands/sidecar.rs: after download extraction
- commands/media.rs: removed single-file fix (now handled globally)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The bundled ffmpeg in the sidecar extract dir lacked execute permissions.
Now sets chmod 755 on Unix when find_ffmpeg locates the bundled binary.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
audio_file, source_file, audio_wav are all optional with serde defaults.
v1 projects have audio_file, v2 projects have source_file + audio_wav.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Projects now save as folders containing .vtn + audio.wav:
My Transcript/
My Transcript.vtn
audio.wav
Audio handling:
- Always extract to 22kHz mono WAV on import (all formats, not just video)
- Prevents WebAudio crash from decoding large MP3/FLAC/OGG to PCM in memory
- WAV saved alongside .vtn on project save (moved from temp)
- Sidecar still uses original file (does its own conversion)
Project format v2:
- source_file: original import path (for re-extraction)
- audio_wav: relative path to extracted WAV (portable)
Re-link on open:
- If audio.wav exists → load directly
- If missing but source exists → re-extract automatically
- If both missing → dialog to locate file via file picker
- V1 project migration: extracts WAV on first open
New Rust commands: check_file_exists, copy_file, create_dir
extract_audio: now accepts optional output_path, uses 22kHz sample rate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AI provider:
- Extract configureAIProvider() from saveSettings for reuse
- Call it on app startup after sidecar is ready (was only called on Save)
- Call it after first-time sidecar download completes
- Sidecar now receives correct Ollama URL/model immediately
Video extraction:
- Hide ffmpeg console window on Windows (CREATE_NO_WINDOW flag)
- Show "Extracting audio from video..." overlay with spinner during extraction
- UI stays responsive while ffmpeg runs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Video files (MP4, MKV, etc.) are now processed with ffmpeg to extract
audio to a temp WAV file before loading into wavesurfer. This prevents
the WebView crash caused by trying to fetch multi-GB files into memory.
- New extract_audio Tauri command uses ffmpeg (sidecar-bundled or system)
- Frontend detects video extensions and extracts audio automatically
- User-friendly error if ffmpeg is not installed with install instructions
- Reverted wavesurfer MediaElement approach in favor of clean extraction
- Added FFmpeg install guide to USER_GUIDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CSP: Add blob: to connect-src/img-src/media-src for wavesurfer.js audio
playback. Add http://tauri.localhost to default-src for devtools.
pyannote: sys.modules block didn't work — pyannote still uses AudioDecoder
unconditionally. New approach: monkey-patch Audio.__call__ in diarize.py
to use torchaudio.load() directly, bypassing the broken torchcodec path.
Patch runs once before pipeline loading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- DevTools off by default (no more auto-open on launch)
- New "Developer" tab in Settings with a checkbox to toggle devtools
- Toggle takes effect immediately (opens/closes inspector)
- Setting persists: devtools restored on next launch if enabled
- toggle_devtools Tauri command wraps window.open/close_devtools
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CSP: Add connect-src for ipc.localhost and asset.localhost so Tauri IPC
commands and local file loading (waveform, audio playback) work.
pyannote: Block torchcodec in sys.modules at startup so pyannote.audio
falls back to torchaudio for audio decoding. pyannote has a bug where
it uses AudioDecoder unconditionally even when torchcodec import fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Enable Tauri devtools feature so right-click Inspect works in release
- Open devtools automatically on launch for debugging
- Add log_frontend command: frontend can write to ~/.voicetonotes/frontend.log
- Sidecar logs go to %LOCALAPPDATA%/com.voicetonotes.app/sidecar.log
- Frontend logs go to %USERPROFILE%/.voicetonotes/frontend.log
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sidecar now has its own version (1.0.0) and release lifecycle:
- Sidecar tags: sidecar-v1.0.0, sidecar-v1.0.1, etc.
- App tags: v0.2.x (unchanged)
- Sidecar workflow triggers only on python/** changes or manual dispatch
- App release no longer bumps python/pyproject.toml
Sidecar version tracked via sidecar-version.txt in app data dir:
- resolve_sidecar_path() reads version from file instead of CARGO_PKG_VERSION
- download_sidecar() fetches latest sidecar-v* release from Gitea API
- check_sidecar_update() compares local vs remote sidecar versions
- Version file written after successful download
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CI split:
- release.yml: version bump + lightweight app builds (no Python/sidecar)
- build-sidecar.yml: builds CPU + CUDA sidecar variants per platform,
uploads as separate release assets, runs in parallel with app builds
- Sidecar workflow uses retry loop to find release (race with version bump)
Fixes:
- Add reqwest "json" feature for .json() method
- Add explicit type annotations for reqwest Response and bytes::Bytes
- Reuse client instance for download (was using reqwest::get directly)
Bundle targets: deb, rpm, nsis, msi, dmg (all formats, app is small now)
Windows upload finds both *.msi and *-setup.exe
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>