use anyhow::{Context, Result};
use captchaforge::browser_runtime::{drive_browser, BrowserDriveOptions};
use captchaforge::stealth_profiles::named_profile;
use captchaforge::{solve_url, StealthProfile};
#[tokio::main]
async fn main() -> Result<()> {
let mut args = std::env::args().skip(1);
let url = args
.next()
.context("usage: solve_url_simple <url> [--profile <name>]")?;
let profile = parse_profile_arg(args)?;
let target_url = url.clone();
let outcome = drive_browser(
"about:blank",
BrowserDriveOptions::default(),
|page| async move { solve_url(&page, &target_url, profile).await },
)
.await
.context("solve url in browser")?;
match outcome {
None => println!("no captcha detected at {url}"),
Some(r) => println!(
"captcha {} via {:?} in {}ms (confidence={:.2}, verified={:?})",
if r.success { "SOLVED" } else { "FAILED" },
r.method,
r.time_ms,
r.confidence,
r.verified_outcome,
),
}
Ok(())
}
fn parse_profile_arg(mut args: impl Iterator<Item = String>) -> Result<Option<StealthProfile>> {
while let Some(a) = args.next() {
if a == "--profile" {
let name = args.next().context("--profile requires a value")?;
let profile = named_profile(&name).ok_or_else(|| {
anyhow::anyhow!(
"unknown stealth profile {name:?}; try `captchaforge profiles` for the full list"
)
})?;
return Ok(Some(profile));
}
}
Ok(None)
}