use browser_launcher::{Launcher, Options, BrowserType};
use clap::{Parser, ValueEnum};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
#[arg(long)]
starting_url: Option<String>,
#[arg(long)]
browser_flags: Option<String>,
#[arg(long)]
port: Option<u16>,
#[arg(long, value_enum)]
browser: Option<BrowserTypeArg>,
#[arg(long)]
headless: bool,
#[arg(long)]
window_size: Option<String>,
#[arg(long)]
incognito: bool,
#[arg(long)]
disable_gpu: bool,
#[arg(long)]
no_sandbox: bool,
#[arg(long)]
disable_web_security: bool,
#[arg(long)]
allow_insecure_content: bool,
#[arg(long)]
ignore_ssl_errors: bool,
#[arg(long)]
disable_extensions: bool,
#[arg(long)]
disable_plugins: bool,
#[arg(long)]
disable_images: bool,
#[arg(long)]
disable_javascript: bool,
#[arg(long)]
user_agent: Option<String>,
#[arg(long)]
proxy_server: Option<String>,
#[arg(long)]
host_resolver_rules: Option<String>,
#[arg(long)]
user_data_dir: Option<String>,
#[arg(long)]
additional_args: Option<String>,
}
#[derive(Clone, Debug, ValueEnum)]
enum BrowserTypeArg {
Chrome,
Chromium,
Edge,
Brave,
Opera,
Vivaldi,
}
fn main() {
let args = Args::parse();
let mut options = Options::default();
if let Some(url) = args.starting_url {
options.starting_url = Some(url);
}
if let Some(flags) = args.browser_flags {
options.browser_flags = Some(flags.split(',').map(String::from).collect());
}
if let Some(port) = args.port {
options.port = Some(port);
}
if let Some(browser) = args.browser {
options.browser = Some(match browser {
BrowserTypeArg::Chrome => BrowserType::Chrome,
BrowserTypeArg::Chromium => BrowserType::Chromium,
BrowserTypeArg::Edge => BrowserType::Edge,
BrowserTypeArg::Brave => BrowserType::Brave,
BrowserTypeArg::Opera => BrowserType::Opera,
BrowserTypeArg::Vivaldi => BrowserType::Vivaldi,
});
}
options.headless = Some(args.headless);
options.incognito = Some(args.incognito);
options.disable_gpu = Some(args.disable_gpu);
options.no_sandbox = Some(args.no_sandbox);
options.disable_web_security = Some(args.disable_web_security);
options.allow_running_insecure_content = Some(args.allow_insecure_content);
options.ignore_ssl_errors = Some(args.ignore_ssl_errors);
options.disable_extensions = Some(args.disable_extensions);
options.disable_plugins = Some(args.disable_plugins);
options.disable_images = Some(args.disable_images);
options.disable_javascript = Some(args.disable_javascript);
if let Some(window_size) = args.window_size {
if let Some((width, height)) = parse_window_size(&window_size) {
options.window_size = Some((width, height));
} else {
eprintln!("Invalid window size format. Expected WIDTHxHEIGHT (e.g., 1920x1080)");
std::process::exit(1);
}
}
options.user_agent = args.user_agent;
options.proxy_server = args.proxy_server;
options.host_resolver_rules = args.host_resolver_rules;
options.user_data_dir = args.user_data_dir;
if let Some(additional_args) = args.additional_args {
options.additional_args = Some(additional_args.split(',').map(String::from).collect());
}
let mut launcher = Launcher::new(options);
match launcher.launch() {
Ok(mut launched_browser) => {
println!("Launched browser with PID: {}", launched_browser.pid);
let _ = launched_browser
.process
.wait()
.map_err(|e: std::io::Error| e.to_string())
.unwrap();
println!("Browser process has exited.");
}
Err(e) => {
eprintln!("Error launching browser: {}", e);
std::process::exit(1);
}
}
}
fn parse_window_size(size: &str) -> Option<(u32, u32)> {
let parts: Vec<&str> = size.split('x').collect();
if parts.len() == 2 {
if let (Ok(width), Ok(height)) = (parts[0].parse::<u32>(), parts[1].parse::<u32>()) {
Some((width, height))
} else {
None
}
} else {
None
}
}