browser_info/
lib.rs

1//! # browser-info
2//!
3//! Cross-platform library for retrieving active browser URL and detailed information.
4//!
5//! Built on top of `active-win-pos-rs` for reliable window detection, with specialized
6//! browser information extraction capabilities.
7//!
8//! ## Quick Start
9//!
10//! ```rust
11//! use browser_info::get_active_browser_info;
12//!
13//! match get_active_browser_info() {
14//!     Ok(info) => {
15//!         println!("Current URL: {}", info.url);
16//!         println!("Browser: {}", info.browser_name);
17//!         println!("Title: {}", info.title);
18//!     }
19//!     Err(e) => eprintln!("Error: {}", e),
20//! }
21//! ```
22
23//================================================================================================
24// Import Section
25//================================================================================================
26
27use 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//================================================================================================
45// Data Types & Module Variables
46//================================================================================================
47
48#[derive(Debug, Clone, Copy)]
49pub enum ExtractionMethod {
50    /// Auto decision (PowerShell優先 - 推奨)
51    Auto,
52    /// Chrome DevTools Protocol (詳細情報取得 - デバッグモード必要)
53    DevTools,
54    /// PowerShell (高速・互換性重視)
55    PowerShell,
56}
57
58/// [derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
59pub struct BrowserInfo {
60    /// Current URL displayed in the browser
61    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    /// Process ID
69    pub process_id: u64,
70    /// Window position and size
71    pub window_position: WindowPosition,
72}
73
74/// Browser type classification
75#[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/// Window position and dimensions
88#[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
96//================================================================================================
97// procedure
98//================================================================================================
99
100/// Retrieve information about the currently active browser
101///
102/// This function combines window detection (via `active-win-pos-rs`) with
103/// specialized browser information extraction.
104///
105/// # Examples
106///
107/// ```rust
108/// use browser_info::get_active_browser_info;
109///
110/// match get_active_browser_info() {
111///     Ok(info) => {
112///         println!("URL: {}", info.url);
113///         println!("Browser: {:?}", info.browser_type);
114///     }
115///     Err(e) => eprintln!("Failed to get browser info: {}", e),
116/// }
117/// ```
118pub fn get_active_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
119    // Step 0: Check if the active window is browser
120    if !is_browser_active() {
121        return Err(BrowserInfoError::NotABrowser);
122    }
123
124    // Step 1: Definitely browser. Get active window using active-win-pos-rs
125    let window = get_active_window().map_err(|_| BrowserInfoError::WindowNotFound)?;
126
127    // Step 2: Verify it's a browser window
128    let browser_type = browser_detection::classify_browser(&window)?;
129
130    // Step 3: Extract URL using platform-specific methods
131    let url = url_extraction::extract_url(&window, &browser_type)?;
132
133    // Step 4: Get additional browser metadata
134    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
154/// Get only the URL from the active browser (lightweight version)
155pub fn get_active_browser_url() -> Result<String, BrowserInfoError> {
156    // Step 0: 高速事前チェック
157    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
167/// Check if the currently active window is a browser
168pub 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
176/// 高速・互換性重視(PowerShell方式)
177pub fn get_browser_info_safe() -> Result<BrowserInfo, BrowserInfoError> {
178    get_active_browser_info()
179}
180
181/// 詳細情報重視(Chrome DevTools - デバッグモード必要)
182#[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/// 後方互換性のためのエイリアス
191#[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
199/// デフォルト(自動判定・推奨)- PowerShell優先
200pub async fn get_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
201    // 1. PowerShell方式を最優先(高速・確実)
202    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    // 2. PowerShell失敗時のみDevTools
213    #[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
224/// 明示的な方法指定
225pub 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}