use std::path::PathBuf;
use url::Url;
use anyhow::Result;
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD as BASE64;
use clipboard_rs::Clipboard;
use clipboard_rs::ClipboardContext;
use clipboard_rs::common::RustImage;
use clipboard_rs::common::RustImageData;
pub fn clipboard_file_paths() -> Vec<PathBuf> {
let ctx = match ClipboardContext::new() {
Ok(ctx) => ctx,
Err(_) => return Vec::new(),
};
if let Ok(files) = ctx.get_files() {
let paths: Vec<PathBuf> = files.into_iter().map(PathBuf::from).collect();
if !paths.is_empty() {
return paths;
}
}
if let Ok(text) = ctx.get_text() {
return parse_uri_list(&text);
}
Vec::new()
}
pub fn read_text() -> Option<String> {
let ctx = ClipboardContext::new().ok()?;
ctx.get_text().ok()
}
pub fn read_image_png_base64() -> Option<String> {
let ctx = ClipboardContext::new().ok()?;
let img = ctx.get_image().ok()?;
let png = img.to_png().ok()?;
Some(BASE64.encode(png.get_bytes()))
}
pub fn set_text(text: &str) -> Result<()> {
let ctx =
ClipboardContext::new().map_err(|e| anyhow::anyhow!("Failed to access clipboard: {e}"))?;
ctx.set_text(text.to_string())
.map_err(|e| anyhow::anyhow!("Failed to set clipboard text: {e}"))?;
Ok(())
}
pub fn set_image(img: image::DynamicImage) -> Result<()> {
let ctx =
ClipboardContext::new().map_err(|e| anyhow::anyhow!("Failed to access clipboard: {e}"))?;
let rust_img = RustImageData::from_dynamic_image(img);
ctx.set_image(rust_img)
.map_err(|e| anyhow::anyhow!("Failed to set clipboard image: {e}"))?;
Ok(())
}
pub fn get_image_as_base64() -> Option<String> {
let ctx = ClipboardContext::new().ok()?;
let img = ctx.get_image().ok()?;
let png = img.to_png().ok()?;
Some(BASE64.encode(png.get_bytes()))
}
pub fn clear() -> Result<()> {
let ctx =
ClipboardContext::new().map_err(|e| anyhow::anyhow!("Failed to access clipboard: {e}"))?;
ctx.clear()
.map_err(|e| anyhow::anyhow!("Failed to clear clipboard: {e}"))?;
Ok(())
}
pub fn parse_uri_list(text: &str) -> Vec<PathBuf> {
text.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with('#'))
.filter_map(|line| {
if line.starts_with("file://") {
Url::parse(line).ok()?.to_file_path().ok()
} else if line == "cut" || line == "copy" {
None } else {
Some(PathBuf::from(line))
}
})
.collect()
}