mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
feat: add CLI for binary management (Python + JavaScript)
Adds install, info, update, and clear-cache subcommands with visible download progress. Python: `python -m cloakbrowser install`. JavaScript: `npx cloakbrowser install`. Useful for Dockerfiles where silent first-use downloads are hard to debug. Closes #43.
This commit is contained in:
@@ -313,6 +313,17 @@ Supports all the same options as `launch_context()`: `proxy`, `user_agent`, `vie
|
||||
|
||||
Async version: `launch_persistent_context_async()`.
|
||||
|
||||
### CLI
|
||||
|
||||
Pre-download the binary or check installation status from the command line:
|
||||
|
||||
```bash
|
||||
python -m cloakbrowser install # Download binary with progress output
|
||||
python -m cloakbrowser info # Show version, path, platform
|
||||
python -m cloakbrowser update # Check for and download newer binary
|
||||
python -m cloakbrowser clear-cache # Remove cached binaries
|
||||
```
|
||||
|
||||
### Utility Functions
|
||||
|
||||
```python
|
||||
@@ -706,6 +717,15 @@ COPY your_script.py /app/
|
||||
CMD ["python", "your_script.py"]
|
||||
```
|
||||
|
||||
**Building your own image from pip** — use `python -m cloakbrowser install` to download the binary during build with visible progress:
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.12-slim
|
||||
RUN pip install cloakbrowser && python -m cloakbrowser install
|
||||
COPY your_script.py /app/
|
||||
CMD ["python", "/app/your_script.py"]
|
||||
```
|
||||
|
||||
**Building from source** — a [`Dockerfile`](Dockerfile) is also included if you prefer to build your own image:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
"""CLI for cloakbrowser — download and manage the stealth Chromium binary.
|
||||
|
||||
Usage:
|
||||
python -m cloakbrowser install # Download binary (with progress)
|
||||
python -m cloakbrowser info # Show binary version, path, platform
|
||||
python -m cloakbrowser update # Check for and download newer binary
|
||||
python -m cloakbrowser clear-cache # Remove cached binaries
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
||||
def _setup_logging() -> None:
|
||||
"""Route cloakbrowser logger to stderr with clean output."""
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(message)s",
|
||||
stream=sys.stderr,
|
||||
force=True,
|
||||
)
|
||||
# Suppress noisy HTTP request logs from httpx
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
|
||||
|
||||
def cmd_install(args: argparse.Namespace) -> None:
|
||||
from .download import ensure_binary
|
||||
|
||||
path = ensure_binary()
|
||||
print(path)
|
||||
|
||||
|
||||
def cmd_info(args: argparse.Namespace) -> None:
|
||||
from .config import get_local_binary_override
|
||||
from .download import binary_info
|
||||
|
||||
info = binary_info()
|
||||
override = get_local_binary_override()
|
||||
|
||||
print(f"Version: {info['version']}")
|
||||
print(f"Platform: {info['platform']}")
|
||||
print(f"Binary: {info['binary_path']}")
|
||||
print(f"Installed: {info['installed']}")
|
||||
print(f"Cache: {info['cache_dir']}")
|
||||
if override:
|
||||
print(f"Override: {override} (CLOAKBROWSER_BINARY_PATH)")
|
||||
|
||||
|
||||
def cmd_update(args: argparse.Namespace) -> None:
|
||||
from .download import check_for_update
|
||||
|
||||
logger = logging.getLogger("cloakbrowser")
|
||||
logger.info("Checking for updates...")
|
||||
new_version = check_for_update()
|
||||
if new_version:
|
||||
print(f"Updated to Chromium {new_version}")
|
||||
else:
|
||||
print("Already up to date.")
|
||||
|
||||
|
||||
def cmd_clear_cache(args: argparse.Namespace) -> None:
|
||||
from .config import get_cache_dir
|
||||
from .download import clear_cache
|
||||
|
||||
if not get_cache_dir().exists():
|
||||
print("No cache to clear.")
|
||||
return
|
||||
clear_cache()
|
||||
print("Cache cleared.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="cloakbrowser",
|
||||
description="Manage the CloakBrowser stealth Chromium binary.",
|
||||
)
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
|
||||
sub.add_parser("install", help="Download the Chromium binary")
|
||||
sub.add_parser("info", help="Show binary version, path, and platform")
|
||||
sub.add_parser("update", help="Check for and download a newer binary")
|
||||
sub.add_parser("clear-cache", help="Remove all cached binaries")
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(2)
|
||||
|
||||
_setup_logging()
|
||||
|
||||
commands = {
|
||||
"install": cmd_install,
|
||||
"info": cmd_info,
|
||||
"update": cmd_update,
|
||||
"clear-cache": cmd_clear_cache,
|
||||
}
|
||||
|
||||
try:
|
||||
commands[args.command](args)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -133,6 +133,17 @@ const browser = await launch({ proxy: 'http://proxy:8080', geoip: true, timezone
|
||||
|
||||
> **Note:** For rotating residential proxies, the DNS-resolved IP may differ from the exit IP. Pass explicit `timezone`/`locale` in those cases.
|
||||
|
||||
### CLI
|
||||
|
||||
Pre-download the binary or check installation status from the command line:
|
||||
|
||||
```bash
|
||||
npx cloakbrowser install # Download binary with progress output
|
||||
npx cloakbrowser info # Show version, path, platform
|
||||
npx cloakbrowser update # Check for and download newer binary
|
||||
npx cloakbrowser clear-cache # Remove cached binaries
|
||||
```
|
||||
|
||||
### Utilities
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
"import": "./dist/puppeteer.js"
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"cloakbrowser": "./dist/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* CLI for cloakbrowser — download and manage the stealth Chromium binary.
|
||||
*
|
||||
* Usage:
|
||||
* npx cloakbrowser install # Download binary (with progress)
|
||||
* npx cloakbrowser info # Show binary version, path, platform
|
||||
* npx cloakbrowser update # Check for and download newer binary
|
||||
* npx cloakbrowser clear-cache # Remove cached binaries
|
||||
*/
|
||||
|
||||
import { ensureBinary, binaryInfo, checkForUpdate, clearCache } from "./download.js";
|
||||
import { getLocalBinaryOverride, getCacheDir } from "./config.js";
|
||||
import fs from "node:fs";
|
||||
|
||||
const USAGE = `Usage: cloakbrowser <command>
|
||||
|
||||
Commands:
|
||||
install Download the Chromium binary
|
||||
info Show binary version, path, and platform
|
||||
update Check for and download a newer binary
|
||||
clear-cache Remove all cached binaries`;
|
||||
|
||||
async function cmdInstall(): Promise<void> {
|
||||
const binaryPath = await ensureBinary();
|
||||
console.log(binaryPath);
|
||||
}
|
||||
|
||||
function cmdInfo(): void {
|
||||
const info = binaryInfo();
|
||||
const override = getLocalBinaryOverride();
|
||||
|
||||
console.log(`Version: ${info.version}`);
|
||||
console.log(`Platform: ${info.platform}`);
|
||||
console.log(`Binary: ${info.binaryPath}`);
|
||||
console.log(`Installed: ${info.installed}`);
|
||||
console.log(`Cache: ${info.cacheDir}`);
|
||||
if (override) {
|
||||
console.log(`Override: ${override} (CLOAKBROWSER_BINARY_PATH)`);
|
||||
}
|
||||
}
|
||||
|
||||
async function cmdUpdate(): Promise<void> {
|
||||
console.error("Checking for updates...");
|
||||
const newVersion = await checkForUpdate();
|
||||
if (newVersion) {
|
||||
console.log(`Updated to Chromium ${newVersion}`);
|
||||
} else {
|
||||
console.log("Already up to date.");
|
||||
}
|
||||
}
|
||||
|
||||
function cmdClearCache(): void {
|
||||
const cacheDir = getCacheDir();
|
||||
if (!fs.existsSync(cacheDir)) {
|
||||
console.log("No cache to clear.");
|
||||
return;
|
||||
}
|
||||
clearCache();
|
||||
console.log("Cache cleared.");
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const command = process.argv[2];
|
||||
|
||||
if (!command || command === "--help" || command === "-h") {
|
||||
console.log(USAGE);
|
||||
process.exit(command ? 0 : 2);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (command) {
|
||||
case "install":
|
||||
await cmdInstall();
|
||||
break;
|
||||
case "info":
|
||||
cmdInfo();
|
||||
break;
|
||||
case "update":
|
||||
await cmdUpdate();
|
||||
break;
|
||||
case "clear-cache":
|
||||
cmdClearCache();
|
||||
break;
|
||||
default:
|
||||
console.error(`Unknown command: ${command}\n`);
|
||||
console.log(USAGE);
|
||||
process.exit(2);
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
console.error(`Error: ${message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -58,6 +58,9 @@ geoip = ["geoip2>=4.0"]
|
||||
patchright = ["patchright>=1.40"]
|
||||
dev = ["pytest>=7.0", "pytest-asyncio>=0.23"]
|
||||
|
||||
[project.scripts]
|
||||
cloakbrowser = "cloakbrowser.__main__:main"
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/CloakHQ/CloakBrowser"
|
||||
Documentation = "https://github.com/CloakHQ/CloakBrowser#readme"
|
||||
|
||||
Reference in New Issue
Block a user