| use pyo3::prelude::*; |
| use pyo3::wrap_pyfunction; |
| use std::fs::File; |
| use std::io::Write; |
| use std::process::Command; |
| use uuid::Uuid; |
|
|
| #[pyfunction] |
| fn combine_clips(clips: Vec<String>) -> PyResult<String> { |
| let paths: Vec<&str> = clips.iter().map(|s| s.as_str()).collect(); |
| concat_videos(paths) |
|
|
| } |
|
|
| fn concat_videos(clips: Vec<&str>) -> PyResult<String> { |
| |
| let list_file = format!("/tmp/clips_{}.txt", Uuid::new_v4()); |
| let mut file = File::create(&list_file) |
| .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))?; |
| for clip in &clips { writeln!(file, "file '{}'", clip) |
| .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))?; |
| } |
|
|
| |
| let output_file = format!("/tmp/final_video_{}.mp4", Uuid::new_v4()); |
| let status = Command::new("ffmpeg") |
| .args(&[ |
| "-y", |
| "-f", "concat", |
| "-safe", "0", |
| "-i", &list_file, |
| "-c", "copy", |
| &output_file, |
| ]) |
| .status() |
| .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?; |
|
|
| if status.success() { |
| Ok(output_file) |
| } else { |
| Err(pyo3::exceptions::PyRuntimeError::new_err("FFmpeg command failed")) |
| } |
|
|
| } |
|
|
| #[pymodule] |
| fn rust_combiner(_py: Python, m: &PyModule) -> PyResult<()> { |
| m.add_function(wrap_pyfunction!(combine_clips, m)?)?; |
| Ok(()) |
| } |