Phase 1 (Infrastructure): - Docs: README.md, AGENTS.md, CHANGELOG.md - Tests: 26 tests (modes_test, filetree_api_test) - Examples: examples/sample.md, sample.json - CI/CD: .gitea/workflows/test.yml, release.yml - Runner: configuration scripts and guides Phase 2 (Quality): - Code quality: rustfmt/clippy config - Security: environment variables - Test coverage: 62 tests (+36) - Documentation: CONTRIBUTING.md, docs/api.yaml - Showcase: demo_features.md, developer_quickstart.md Test coverage: 75% Test pass rate: 100%
62 lines
1.9 KiB
Rust
62 lines
1.9 KiB
Rust
use axum::response::Json;
|
|
use std::sync::Mutex;
|
|
|
|
use crate::audio;
|
|
|
|
static CMD_QUEUE: Mutex<Vec<(String, Option<String>)>> = Mutex::new(Vec::new());
|
|
|
|
pub async fn post_command(
|
|
Json(body): Json<serde_json::Value>,
|
|
) -> impl axum::response::IntoResponse {
|
|
let cmd = body["cmd"].as_str().unwrap_or("").to_string();
|
|
let val = body["val"].as_str().map(|s| s.to_string());
|
|
let out = body["out"].as_str().map(|s| s.to_string());
|
|
|
|
if cmd == "test_voice" {
|
|
let lang = val.as_deref().unwrap_or("zh_TW");
|
|
let voice_name = audio::voice_for_lang(lang);
|
|
let phrase = audio::phrase_for_lang(lang);
|
|
if let Some(d) = out.as_deref() {
|
|
if !d.is_empty() {
|
|
std::process::Command::new("SwitchAudioSource")
|
|
.args(["-t", "output", "-s", d])
|
|
.output()
|
|
.ok();
|
|
}
|
|
}
|
|
std::process::Command::new("say")
|
|
.args(["-v", &voice_name, &phrase])
|
|
.spawn()
|
|
.ok();
|
|
} else if cmd == "vol_up" {
|
|
std::process::Command::new("osascript")
|
|
.args([
|
|
"-e",
|
|
"set volume output volume (output volume of (get volume settings)) + 10",
|
|
])
|
|
.output()
|
|
.ok();
|
|
} else if cmd == "vol_down" {
|
|
std::process::Command::new("osascript")
|
|
.args([
|
|
"-e",
|
|
"set volume output volume (output volume of (get volume settings)) - 10",
|
|
])
|
|
.output()
|
|
.ok();
|
|
} else {
|
|
CMD_QUEUE.lock().unwrap().push((cmd, val));
|
|
}
|
|
|
|
Json(serde_json::json!({"ok": true}))
|
|
}
|
|
|
|
pub async fn get_commands() -> Json<serde_json::Value> {
|
|
let mut queue = CMD_QUEUE.lock().unwrap();
|
|
let cmds: Vec<_> = queue
|
|
.drain(..)
|
|
.map(|(c, v)| serde_json::json!({"cmd": c, "val": v}))
|
|
.collect();
|
|
Json(serde_json::json!(cmds))
|
|
}
|