use crate::error::SubError;
use std::path::Path;
use std::process::Command;
use which::which;
pub fn align_subtitle(video: &Path, srt: &Path, alass_path: Option<&str>) -> Result<(), SubError> {
let alass = if let Some(p) = alass_path.filter(|s| !s.is_empty()) {
std::path::PathBuf::from(p)
} else {
which("alass")
.or_else(|_| which("alass-cli"))
.map_err(|_| SubError::AlassNotFound)?
};
align_with_binary(&alass, video, srt)
}
fn align_with_binary(alass: &Path, video: &Path, srt: &Path) -> Result<(), SubError> {
let backup = srt.with_extension("bak.srt");
let run_result = Command::new(alass)
.arg(video)
.arg(srt)
.arg(&backup)
.output()
.map_err(|e| SubError::AlassFailed(e.to_string()))?;
if !run_result.status.success() {
let stderr = String::from_utf8_lossy(&run_result.stderr).to_string();
return Err(SubError::AlassFailed(stderr));
}
std::fs::copy(&backup, srt).map_err(SubError::Io)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn align_returns_error_when_alass_missing() {
let result = align_with_binary(
Path::new("nonexistent_alass_binary_xyz"),
Path::new("video.mp4"),
Path::new("sub.srt"),
);
assert!(matches!(result, Err(SubError::AlassFailed(_))));
}
}