Project folders, always-extract audio, re-link support
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>
This commit is contained in:
@@ -7,15 +7,18 @@ use std::os::windows::process::CommandExt;
|
||||
/// Extract audio from a video file to a WAV file using ffmpeg.
|
||||
/// Returns the path to the extracted audio file.
|
||||
#[tauri::command]
|
||||
pub fn extract_audio(file_path: String) -> Result<String, String> {
|
||||
pub fn extract_audio(file_path: String, output_path: Option<String>) -> Result<String, String> {
|
||||
let input = PathBuf::from(&file_path);
|
||||
if !input.exists() {
|
||||
return Err(format!("File not found: {}", file_path));
|
||||
}
|
||||
|
||||
// Output to a temp WAV file next to the original or in temp dir
|
||||
// Use provided output path, or fall back to a temp WAV file
|
||||
let stem = input.file_stem().unwrap_or_default().to_string_lossy();
|
||||
let output = std::env::temp_dir().join(format!("{stem}_audio.wav"));
|
||||
let output = match output_path {
|
||||
Some(ref p) => PathBuf::from(p),
|
||||
None => std::env::temp_dir().join(format!("{stem}_audio.wav")),
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"[media] Extracting audio: {} -> {}",
|
||||
@@ -35,7 +38,7 @@ pub fn extract_audio(file_path: String) -> Result<String, String> {
|
||||
"-acodec",
|
||||
"pcm_s16le", // WAV PCM 16-bit
|
||||
"-ar",
|
||||
"16000", // 16kHz (optimal for whisper)
|
||||
"22050", // 22kHz mono for better playback quality
|
||||
"-ac",
|
||||
"1", // Mono
|
||||
])
|
||||
@@ -63,6 +66,23 @@ pub fn extract_audio(file_path: String) -> Result<String, String> {
|
||||
Ok(output.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn check_file_exists(path: String) -> bool {
|
||||
std::path::Path::new(&path).exists()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn copy_file(src: String, dst: String) -> Result<(), String> {
|
||||
std::fs::copy(&src, &dst).map_err(|e| format!("Failed to copy file: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn create_dir(path: String) -> Result<(), String> {
|
||||
std::fs::create_dir_all(&path).map_err(|e| format!("Failed to create directory: {e}"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Find ffmpeg binary — check sidecar directory first, then system PATH.
|
||||
fn find_ffmpeg() -> Option<String> {
|
||||
// Check sidecar extract dir (ffmpeg is bundled with the sidecar)
|
||||
|
||||
Reference in New Issue
Block a user