use crate::error::{NpcError, Result};
use std::collections::HashMap;
use std::path::Path;
pub fn capture_screenshot(full: bool) -> Result<HashMap<String, String>> {
let dir = shellexpand::tilde("~/.npcsh/screenshots").to_string();
std::fs::create_dir_all(&dir).map_err(|e| NpcError::FileLoad {
path: dir.clone(),
source: e,
})?;
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S").to_string();
let filename = format!("screenshot_{}.png", timestamp);
let file_path = format!("{}/{}", dir, filename);
let os = std::env::consts::OS;
if full {
match os {
"macos" => {
let _ = std::process::Command::new("screencapture")
.arg(&file_path)
.output();
}
"linux" => {
let tools: &[(&str, &[&str])] = &[
("grim", &[]),
("scrot", &[]),
("import", &["-window", "root"]),
("gnome-screenshot", &["-f"]),
];
let mut took = false;
for (cmd, extra) in tools {
if std::process::Command::new("which")
.arg(cmd)
.output()
.map(|o| o.status.success())
.unwrap_or(false)
{
let mut args: Vec<&str> = extra.to_vec();
args.push(&file_path);
let _ = std::process::Command::new(cmd).args(&args).output();
if Path::new(&file_path).exists() {
took = true;
break;
}
}
}
if !took {
return Err(NpcError::Shell("No screenshot tool found".into()));
}
}
_ => return Err(NpcError::Shell(format!("Unsupported OS: {}", os))),
}
} else {
match os {
"macos" => {
let _ = std::process::Command::new("screencapture")
.args(["-i", &file_path])
.output();
}
"linux" => {
if std::process::Command::new("which")
.arg("scrot")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
{
let _ = std::process::Command::new("scrot")
.args(["-s", &file_path])
.output();
} else {
return Err(NpcError::Shell("No interactive screenshot tool".into()));
}
}
_ => return Err(NpcError::Shell(format!("Unsupported OS: {}", os))),
}
}
if Path::new(&file_path).exists() {
let mut r = HashMap::new();
r.insert("filename".into(), filename);
r.insert("file_path".into(), file_path);
Ok(r)
} else {
Err(NpcError::Shell("Screenshot failed".into()))
}
}
pub fn compress_image(image_bytes: &[u8], max_width: u32, max_height: u32) -> Result<Vec<u8>> {
let tmp_in = std::env::temp_dir().join(format!("npc_ci_{}.png", std::process::id()));
let tmp_out = std::env::temp_dir().join(format!("npc_co_{}.jpg", std::process::id()));
std::fs::write(&tmp_in, image_bytes).map_err(|e| NpcError::FileLoad {
path: tmp_in.display().to_string(),
source: e,
})?;
let resize = format!("{}x{}>", max_width, max_height);
let result = std::process::Command::new("convert")
.args([
tmp_in.to_str().unwrap(),
"-resize",
&resize,
"-quality",
"95",
tmp_out.to_str().unwrap(),
])
.output();
let out = match result {
Ok(o) if o.status.success() && tmp_out.exists() => {
std::fs::read(&tmp_out).unwrap_or_else(|_| image_bytes.to_vec())
}
_ => image_bytes.to_vec(),
};
let _ = std::fs::remove_file(&tmp_in);
let _ = std::fs::remove_file(&tmp_out);
Ok(out)
}