use active_win_pos_rs::get_active_window;
use serde::{Deserialize, Serialize};
pub mod browser_detection;
pub mod error;
pub mod url_extraction;
pub mod platform;
pub use error::BrowserInfoError;
#[cfg(any(
all(feature = "devtools", target_os = "windows"),
all(doc, feature = "devtools")
))]
pub use platform::chrome_devtools::ChromeDevToolsExtractor;
#[derive(Debug, Clone, Copy)]
pub enum ExtractionMethod {
Auto,
DevTools,
PowerShell,
}
pub struct BrowserInfo {
pub url: String,
pub title: String,
pub browser_name: String,
pub browser_type: BrowserType,
pub version: Option<String>,
pub tabs_count: Option<u32>,
pub is_incognito: bool,
pub process_id: u64,
pub window_position: WindowPosition,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum BrowserType {
Chrome,
Firefox,
Edge,
Safari,
Brave,
Opera,
Vivaldi,
Unknown(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct WindowPosition {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
pub fn get_active_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
if !is_browser_active() {
return Err(BrowserInfoError::NotABrowser);
}
let window = get_active_window().map_err(|_| BrowserInfoError::WindowNotFound)?;
let browser_type = browser_detection::classify_browser(&window)?;
let url = url_extraction::extract_url(&window, &browser_type)?;
let metadata = browser_detection::get_browser_metadata(&window, &browser_type)?;
Ok(BrowserInfo {
url,
title: window.title,
browser_name: window.app_name,
browser_type,
version: metadata.version,
tabs_count: metadata.tabs_count,
is_incognito: metadata.is_incognito,
process_id: window.process_id,
window_position: WindowPosition {
x: window.position.x,
y: window.position.y,
width: window.position.width,
height: window.position.height,
},
})
}
pub fn get_active_browser_url() -> Result<String, BrowserInfoError> {
if !is_browser_active() {
return Err(BrowserInfoError::NotABrowser);
}
let window = get_active_window().map_err(|_| BrowserInfoError::WindowNotFound)?;
let browser_type = browser_detection::classify_browser(&window)?;
url_extraction::extract_url(&window, &browser_type)
}
pub fn is_browser_active() -> bool {
if let Ok(window) = get_active_window() {
browser_detection::classify_browser(&window).is_ok()
} else {
false
}
}
pub fn get_browser_info_safe() -> Result<BrowserInfo, BrowserInfoError> {
get_active_browser_info()
}
#[cfg(any(
all(feature = "devtools", target_os = "windows"),
all(doc, feature = "devtools")
))]
pub async fn get_browser_info_detailed() -> Result<BrowserInfo, BrowserInfoError> {
ChromeDevToolsExtractor::extract_browser_info().await
}
#[cfg(any(
all(feature = "devtools", target_os = "windows"),
all(doc, feature = "devtools")
))]
pub async fn get_browser_info_fast() -> Result<BrowserInfo, BrowserInfoError> {
get_browser_info_detailed().await
}
pub async fn get_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
match get_browser_info_safe() {
Ok(info) => {
println!("✅ Using PowerShell method (fastest)");
return Ok(info);
}
Err(e) => {
println!("⚠️ PowerShell failed: {e}, trying DevTools...");
}
}
#[cfg(all(feature = "devtools", target_os = "windows"))]
if ChromeDevToolsExtractor::is_available().await {
println!("🔄 Fallback to Chrome DevTools Protocol");
return ChromeDevToolsExtractor::extract_browser_info().await;
}
Err(BrowserInfoError::Other(
"All extraction methods failed".to_string(),
))
}
pub async fn get_browser_info_with_method(
method: ExtractionMethod,
) -> Result<BrowserInfo, BrowserInfoError> {
match method {
ExtractionMethod::Auto => get_browser_info().await,
#[cfg(any(
all(feature = "devtools", target_os = "windows"),
all(doc, feature = "devtools")
))]
ExtractionMethod::DevTools => get_browser_info_detailed().await,
#[cfg(not(any(
all(feature = "devtools", target_os = "windows"),
all(doc, feature = "devtools")
)))]
ExtractionMethod::DevTools => Err(BrowserInfoError::Other(
"DevTools feature not available on this platform".to_string(),
)),
ExtractionMethod::PowerShell => get_browser_info_safe(),
}
}