use crate::domain::entities::Project; use crate::domain::value_objects::TrackId; use anyhow::{Result, anyhow}; /// Ajusta o fator de escala temporal (drift) de uma faixa externa pelo TrackId. /// /// Um `scale != 1.0` indica que o projeto precisará usar o pipeline mkvmerge. #[allow(dead_code)] pub struct AdjustDrift; impl AdjustDrift { #[allow(dead_code)] pub fn execute(project: &mut Project, id: TrackId, scale: f64) -> Result<()> { if scale <= 0.0 { return Err(anyhow!("O fator de escala deve ser maior que zero: {}", scale)); } let track = project .find_track_mut(id) .ok_or_else(|| anyhow!("Faixa não encontrada: {:?}", id))?; track.set_drift_scale(scale); Ok(()) } } #[cfg(test)] mod tests { use super::*; use crate::application::use_cases::add_audio_track::AddAudioTrack; use crate::domain::entities::{MkvOutput, VideoFile}; use crate::domain::value_objects::{FilePath, SyncOffset, TrackLanguage}; fn make_project() -> Project { Project::new( VideoFile::new(FilePath::from("input.mkv")), MkvOutput::new(FilePath::from("output.mkv")), ) .unwrap() } #[test] fn ajusta_drift_existente() { let mut p = make_project(); let lang = TrackLanguage::new("por").unwrap(); AddAudioTrack::execute( &mut p, FilePath::from("audio.aac"), SyncOffset::default(), lang, false, String::new(), 1.0, ) .unwrap(); let id = p.tracks[0].id(); AdjustDrift::execute(&mut p, id, 0.99983).unwrap(); assert!((p.tracks[0].drift_scale() - 0.99983).abs() < 1e-9); } #[test] fn erro_se_id_inexistente() { let mut p = make_project(); let result = AdjustDrift::execute(&mut p, TrackId::new(99), 0.99983); assert!(result.is_err()); } #[test] fn erro_se_scale_zero() { let mut p = make_project(); let lang = TrackLanguage::new("por").unwrap(); AddAudioTrack::execute( &mut p, FilePath::from("audio.aac"), SyncOffset::default(), lang, false, String::new(), 1.0, ) .unwrap(); let id = p.tracks[0].id(); let result = AdjustDrift::execute(&mut p, id, 0.0); assert!(result.is_err()); } }