feat: auto-detect timezone/locale from proxy IP via geoip

Adds geoip=True parameter to launch(), launch_async(), and
launch_context(). Resolves proxy exit IP → MaxMind GeoLite2-City
lookup → timezone + locale. Downloads ~70MB DB on first use from
P3TERX mirror, caches in ~/.cloakbrowser/geoip/.

Optional deps: pip install cloakbrowser[geoip] / npm install mmdb-lib
Explicit timezone/locale always override auto-detected values.
This commit is contained in:
CloakHQ
2026-03-01 01:53:50 +01:00
parent 59b9d71684
commit 67efadef26
14 changed files with 891 additions and 15 deletions
+22 -1
View File
@@ -26,7 +26,8 @@ export async function launch(options: LaunchOptions = {}): Promise<Browser> {
const puppeteer = await import("puppeteer-core");
const binaryPath = process.env.CLOAKBROWSER_BINARY_PATH || (await ensureBinary());
const args = buildArgs(options);
const resolved = await maybeResolveGeoip(options);
const args = buildArgs({ ...options, ...resolved });
// Puppeteer handles proxy via CLI args, not a separate option.
// Chromium's --proxy-server does NOT support inline credentials,
@@ -66,6 +67,20 @@ export async function launch(options: LaunchOptions = {}): Promise<Browser> {
// Internal
// ---------------------------------------------------------------------------
async function maybeResolveGeoip(
options: LaunchOptions
): Promise<{ timezone?: string; locale?: string }> {
if (!options.geoip || !options.proxy) return { timezone: options.timezone, locale: options.locale };
if (options.timezone && options.locale) return { timezone: options.timezone, locale: options.locale };
const { resolveProxyGeo } = await import("./geoip.js");
const { timezone: geoTz, locale: geoLocale } = await resolveProxyGeo(options.proxy);
return {
timezone: options.timezone ?? geoTz ?? undefined,
locale: options.locale ?? geoLocale ?? undefined,
};
}
function buildArgs(options: LaunchOptions): string[] {
const args: string[] = [];
if (options.stealthArgs !== false) {
@@ -74,5 +89,11 @@ function buildArgs(options: LaunchOptions): string[] {
if (options.args) {
args.push(...options.args);
}
if (options.timezone) {
args.push(`--timezone=${options.timezone}`);
}
if (options.locale) {
args.push(`--lang=${options.locale}`);
}
return args;
}