1use active_win_pos_rs::get_active_window;
28use serde::{Deserialize, Serialize};
29
30pub mod browser_detection;
31pub mod error;
32pub mod url_extraction;
33
34pub mod platform;
35
36pub use error::BrowserInfoError;
37
38#[cfg(any(
39 all(feature = "devtools", target_os = "windows"),
40 all(doc, feature = "devtools")
41))]
42pub use platform::chrome_devtools::ChromeDevToolsExtractor;
43
44#[derive(Debug, Clone, Copy)]
49pub enum ExtractionMethod {
50 Auto,
52 DevTools,
54 PowerShell,
56}
57
58pub struct BrowserInfo {
60 pub url: String,
62 pub title: String,
63 pub browser_name: String,
64 pub browser_type: BrowserType,
65 pub version: Option<String>,
66 pub tabs_count: Option<u32>,
67 pub is_incognito: bool,
68 pub process_id: u64,
70 pub window_position: WindowPosition,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76pub enum BrowserType {
77 Chrome,
78 Firefox,
79 Edge,
80 Safari,
81 Brave,
82 Opera,
83 Vivaldi,
84 Unknown(String),
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
89pub struct WindowPosition {
90 pub x: f64,
91 pub y: f64,
92 pub width: f64,
93 pub height: f64,
94}
95
96pub fn get_active_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
119 if !is_browser_active() {
121 return Err(BrowserInfoError::NotABrowser);
122 }
123
124 let window = get_active_window().map_err(|_| BrowserInfoError::WindowNotFound)?;
126
127 let browser_type = browser_detection::classify_browser(&window)?;
129
130 let url = url_extraction::extract_url(&window, &browser_type)?;
132
133 let metadata = browser_detection::get_browser_metadata(&window, &browser_type)?;
135
136 Ok(BrowserInfo {
137 url,
138 title: window.title,
139 browser_name: window.app_name,
140 browser_type,
141 version: metadata.version,
142 tabs_count: metadata.tabs_count,
143 is_incognito: metadata.is_incognito,
144 process_id: window.process_id,
145 window_position: WindowPosition {
146 x: window.position.x,
147 y: window.position.y,
148 width: window.position.width,
149 height: window.position.height,
150 },
151 })
152}
153
154pub fn get_active_browser_url() -> Result<String, BrowserInfoError> {
156 if !is_browser_active() {
158 return Err(BrowserInfoError::NotABrowser);
159 }
160
161 let window = get_active_window().map_err(|_| BrowserInfoError::WindowNotFound)?;
162
163 let browser_type = browser_detection::classify_browser(&window)?;
164 url_extraction::extract_url(&window, &browser_type)
165}
166
167pub fn is_browser_active() -> bool {
169 if let Ok(window) = get_active_window() {
170 browser_detection::classify_browser(&window).is_ok()
171 } else {
172 false
173 }
174}
175
176pub fn get_browser_info_safe() -> Result<BrowserInfo, BrowserInfoError> {
178 get_active_browser_info()
179}
180
181#[cfg(any(
183 all(feature = "devtools", target_os = "windows"),
184 all(doc, feature = "devtools")
185))]
186pub async fn get_browser_info_detailed() -> Result<BrowserInfo, BrowserInfoError> {
187 ChromeDevToolsExtractor::extract_browser_info().await
188}
189
190#[cfg(any(
192 all(feature = "devtools", target_os = "windows"),
193 all(doc, feature = "devtools")
194))]
195pub async fn get_browser_info_fast() -> Result<BrowserInfo, BrowserInfoError> {
196 get_browser_info_detailed().await
197}
198
199pub async fn get_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
201 match get_browser_info_safe() {
203 Ok(info) => {
204 println!("✅ Using PowerShell method (fastest)");
205 return Ok(info);
206 }
207 Err(e) => {
208 println!("⚠️ PowerShell failed: {e}, trying DevTools...");
209 }
210 }
211
212 #[cfg(all(feature = "devtools", target_os = "windows"))]
214 if ChromeDevToolsExtractor::is_available().await {
215 println!("🔄 Fallback to Chrome DevTools Protocol");
216 return ChromeDevToolsExtractor::extract_browser_info().await;
217 }
218
219 Err(BrowserInfoError::Other(
220 "All extraction methods failed".to_string(),
221 ))
222}
223
224pub async fn get_browser_info_with_method(
226 method: ExtractionMethod,
227) -> Result<BrowserInfo, BrowserInfoError> {
228 match method {
229 ExtractionMethod::Auto => get_browser_info().await,
230 #[cfg(any(
231 all(feature = "devtools", target_os = "windows"),
232 all(doc, feature = "devtools")
233 ))]
234 ExtractionMethod::DevTools => get_browser_info_detailed().await,
235 #[cfg(not(any(
236 all(feature = "devtools", target_os = "windows"),
237 all(doc, feature = "devtools")
238 )))]
239 ExtractionMethod::DevTools => Err(BrowserInfoError::Other(
240 "DevTools feature not available on this platform".to_string(),
241 )),
242 ExtractionMethod::PowerShell => get_browser_info_safe(),
243 }
244}