voicepeak_cli/
voicepeak.rs

1use std::process::Command as ProcessCommand;
2
3const VOICEPEAK_PATH: &str = "/Applications/voicepeak.app/Contents/MacOS/voicepeak";
4
5pub fn list_narrator() {
6    let output = ProcessCommand::new(VOICEPEAK_PATH)
7        .arg("--list-narrator")
8        .output();
9
10    match output {
11        Ok(output) => {
12            print!("{}", String::from_utf8_lossy(&output.stdout));
13        }
14        Err(e) => {
15            eprintln!("Failed to execute voicepeak: {}", e);
16        }
17    }
18}
19
20pub fn list_emotion(narrator: &str) {
21    let output = ProcessCommand::new(VOICEPEAK_PATH)
22        .arg("--list-emotion")
23        .arg(narrator)
24        .output();
25
26    match output {
27        Ok(output) => {
28            print!("{}", String::from_utf8_lossy(&output.stdout));
29        }
30        Err(e) => {
31            eprintln!("Failed to execute voicepeak: {}", e);
32        }
33    }
34}
35
36pub struct VoicepeakCommand {
37    command: ProcessCommand,
38}
39
40impl VoicepeakCommand {
41    pub fn new() -> Self {
42        Self {
43            command: ProcessCommand::new(VOICEPEAK_PATH),
44        }
45    }
46
47    pub fn text(mut self, text: &str) -> Self {
48        self.command.arg("-s").arg(text);
49        self
50    }
51
52    pub fn narrator(mut self, narrator: &str) -> Self {
53        self.command.arg("-n").arg(narrator);
54        self
55    }
56
57    pub fn emotion(mut self, emotion: &str) -> Self {
58        if !emotion.is_empty() {
59            self.command.arg("-e").arg(emotion);
60        }
61        self
62    }
63
64    pub fn output(mut self, path: &std::path::Path) -> Self {
65        self.command.arg("-o").arg(path);
66        self
67    }
68
69    pub fn speed(mut self, speed: &str) -> Self {
70        self.command.arg("--speed").arg(speed);
71        self
72    }
73
74    pub fn pitch(mut self, pitch: &str) -> Self {
75        self.command.arg("--pitch").arg(pitch);
76        self
77    }
78
79    pub fn execute(self) -> Result<(), Box<dyn std::error::Error>> {
80        self.execute_with_verbose(false)
81    }
82
83    pub fn execute_with_verbose(mut self, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
84        if verbose {
85            let status = self.command.status()?;
86            if !status.success() {
87                return Err("voicepeak command failed".into());
88            }
89        } else {
90            // Suppress output by redirecting to null
91            let output = self.command.output()?;
92            if !output.status.success() {
93                return Err("voicepeak command failed".into());
94            }
95        }
96        Ok(())
97    }
98}
99
100impl Default for VoicepeakCommand {
101    fn default() -> Self {
102        Self::new()
103    }
104}