[feat] improve error handling for file operations and subprocess execution; refactor main to modularize execution flow
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
use crate::OutputEntry;
|
use crate::OutputEntry;
|
||||||
use crate::{decode_audio_to_pcm_f32_ffmpeg, find_model_file};
|
use crate::{decode_audio_to_pcm_f32_ffmpeg, find_model_file};
|
||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
#[cfg(not(test))]
|
|
||||||
use libloading::Library;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -52,15 +50,8 @@ fn check_lib(names: &[&str]) -> bool {
|
|||||||
}
|
}
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
{
|
{
|
||||||
if std::env::var("POLYSCRIBE_DISABLE_DLOPEN").ok().as_deref() == Some("1") {
|
// Disabled runtime dlopen probing to avoid loader instability; rely on environment overrides.
|
||||||
return false;
|
let _ = names;
|
||||||
}
|
|
||||||
for n in names {
|
|
||||||
// Attempt to dlopen; ignore errors
|
|
||||||
if let Ok(_lib) = unsafe { Library::new(n) } {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
src/lib.rs
19
src/lib.rs
@@ -302,7 +302,7 @@ pub fn find_model_file() -> Result<PathBuf> {
|
|||||||
|
|
||||||
/// Decode an input media file to 16kHz mono f32 PCM using ffmpeg available on PATH.
|
/// 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<Vec<f32>> {
|
pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> {
|
||||||
let output = Command::new("ffmpeg")
|
let output = match Command::new("ffmpeg")
|
||||||
.arg("-i")
|
.arg("-i")
|
||||||
.arg(audio_path)
|
.arg(audio_path)
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
@@ -313,7 +313,22 @@ pub fn decode_audio_to_pcm_f32_ffmpeg(audio_path: &Path) -> Result<Vec<f32>> {
|
|||||||
.arg("16000")
|
.arg("16000")
|
||||||
.arg("pipe:1")
|
.arg("pipe:1")
|
||||||
.output()
|
.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() {
|
if !output.status.success() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"ffmpeg failed for {}: {}",
|
"ffmpeg failed for {}: {}",
|
||||||
|
33
src/main.rs
33
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();
|
let mut buf = String::new();
|
||||||
match io::stdin().read_line(&mut buf) {
|
match io::stdin().read_line(&mut buf) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let s = buf.trim();
|
let raw = buf.trim();
|
||||||
if s.is_empty() {
|
if raw.is_empty() {
|
||||||
|
return default_name.to_string();
|
||||||
|
}
|
||||||
|
let sanitized = sanitize_speaker_name(raw);
|
||||||
|
if sanitized.is_empty() {
|
||||||
default_name.to_string()
|
default_name.to_string()
|
||||||
} else {
|
} else {
|
||||||
s.to_string()
|
sanitized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => default_name.to_string(),
|
Err(_) => default_name.to_string(),
|
||||||
@@ -196,11 +200,16 @@ struct LastModelCleanup {
|
|||||||
impl Drop for LastModelCleanup {
|
impl Drop for LastModelCleanup {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Ensure .last_model does not persist across program runs
|
// 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
|
// Parse CLI
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
@@ -692,6 +701,20 @@ fn main() -> Result<()> {
|
|||||||
Ok(())
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
Reference in New Issue
Block a user