diff --git a/src/backend.rs b/src/backend.rs index d770e5b..5e02833 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,8 +1,6 @@ use crate::OutputEntry; use crate::{decode_audio_to_pcm_f32_ffmpeg, find_model_file}; use anyhow::{Context, Result, anyhow}; -#[cfg(not(test))] -use libloading::Library; use std::env; use std::path::Path; @@ -52,15 +50,8 @@ fn check_lib(names: &[&str]) -> bool { } #[cfg(not(test))] { - if std::env::var("POLYSCRIBE_DISABLE_DLOPEN").ok().as_deref() == Some("1") { - return false; - } - for n in names { - // Attempt to dlopen; ignore errors - if let Ok(_lib) = unsafe { Library::new(n) } { - return true; - } - } + // Disabled runtime dlopen probing to avoid loader instability; rely on environment overrides. + let _ = names; false } } diff --git a/src/lib.rs b/src/lib.rs index 480a3d5..92ce9cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -302,7 +302,7 @@ pub fn find_model_file() -> Result { /// Decode an input media file to 16kHz mono f32 PCM using ffmpeg available on PATH. pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result> { - let output = Command::new("ffmpeg") + let output = match Command::new("ffmpeg") .arg("-i") .arg(audio_path) .arg("-f") @@ -313,7 +313,22 @@ pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result> { .arg("16000") .arg("pipe:1") .output() - .with_context(|| format!("Failed to execute ffmpeg for {}", audio_path.display()))?; + { + Ok(o) => o, + Err(e) => { + if e.kind() == std::io::ErrorKind::NotFound { + return Err(anyhow!( + "ffmpeg not found on PATH. Please install ffmpeg and ensure it is available." + )); + } else { + return Err(anyhow!( + "Failed to execute ffmpeg for {}: {}", + audio_path.display(), + e + )); + } + } + }; if !output.status.success() { return Err(anyhow!( "ffmpeg failed for {}: {}", diff --git a/src/main.rs b/src/main.rs index 876f67d..7a89922 100644 --- a/src/main.rs +++ b/src/main.rs @@ -159,11 +159,15 @@ fn prompt_speaker_name_for_path(path: &Path, default_name: &str, enabled: bool) let mut buf = String::new(); match io::stdin().read_line(&mut buf) { Ok(_) => { - let s = buf.trim(); - if s.is_empty() { + let raw = buf.trim(); + if raw.is_empty() { + return default_name.to_string(); + } + let sanitized = sanitize_speaker_name(raw); + if sanitized.is_empty() { default_name.to_string() } else { - s.to_string() + sanitized } } Err(_) => default_name.to_string(), @@ -196,11 +200,16 @@ struct LastModelCleanup { impl Drop for LastModelCleanup { fn drop(&mut self) { // Ensure .last_model does not persist across program runs - let _ = std::fs::remove_file(&self.path); + if let Err(e) = std::fs::remove_file(&self.path) { + // Best-effort cleanup; ignore missing file; warn for other errors + if e.kind() != std::io::ErrorKind::NotFound { + warnlog!("Failed to remove {}: {}", self.path.display(), e); + } + } } } -fn main() -> Result<()> { +fn run() -> Result<()> { // Parse CLI let args = Args::parse(); @@ -692,6 +701,20 @@ fn main() -> Result<()> { Ok(()) } +fn main() { + if let Err(e) = run() { + errorlog!("{}", e); + if VERBOSE.load(Ordering::Relaxed) >= 1 { + let mut src = e.source(); + while let Some(s) = src { + errorlog!("caused by: {}", s); + src = s.source(); + } + } + std::process::exit(1); + } +} + #[cfg(test)] mod tests { use super::*;