Update help msg, icon, & bugfix

- Don't fall back to old browsers if the active one isnt installed
- Remade the icon for the gui
- Better exception info
This commit is contained in:
daijro
2026-03-07 02:20:26 -06:00
parent dd798fda87
commit be0951543b
5 changed files with 96 additions and 60 deletions
+24 -25
View File
@@ -81,7 +81,6 @@ camoufox gui
https://github.com/user-attachments/assets/992b1830-6b21-4024-9165-728854df1473
<details>
<summary>See help message</summary>
@@ -90,33 +89,33 @@ $ python -m camoufox --help
Usage: python -m camoufox [OPTIONS] COMMAND [ARGS]...
╭─ Options ─────────────────────────────────────────────────────────────────────────╮
│ --help Show this message and exit. │
╰───────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ──────────────────────────────────────────────────────────────────────────────────
│ active Print the current active version
│ fetch Install the active version, or a specific version.
│ gui Launch the Camoufox Manager GUI (requires PySide6)
│ list List Camoufox versions
│ path Print the install directory path
│ remove Remove Camoufox data directory, or an installed browser version
Or, remove a specific version:
Select a version: camoufox remove --select
Remove a version: camoufox remove official/stable/134.0.2-beta.20
server Launch a Playwright server
set Interactive selector for versions and settings
Or, pass a specifier to activate directly:
Pin version: camoufox set official/stable/134.0.2-beta.20 │
Auto-update channel: camoufox set official/stable
sync Sync available versions from remote repositories.
test Open the Playwright inspector
version Display version, package, browser, and storage info
╰─────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────────────────────────────────────────
│ --help Show this message and exit.
╰───────────────────────────────────────────────────────────────────────────────────────
╭─ Commands ────────────────────────────────────────────────────────────────────────────╮
│ active Print the current active version │
│ fetch Install the active version, or a specific version │
│ gui Launch the Camoufox Manager GUI (requires PySide6) │
│ list List Camoufox versions │
│ path Print the install directory path │
│ remove Remove downloaded data. By default, this removes everything.
Pass --select to pick a browser version to remove.
server Launch a Playwright server
set Set the active Camoufox version to use & fetch.
By default, this opens an interactive selector for versions and settings.
You can also pass a specifier to activate directly:
Pin version:
│ camoufox set official/stable/134.0.2-beta.20
Automatically find latest in a channel source:
camoufox set official/stable
sync Sync available versions from remote repositories
test Open the Playwright inspector
│ version Display version, package, browser, and storage info │
╰───────────────────────────────────────────────────────────────────────────────────────╯
```
</details>
### `sync`
Pull a list of release assets from GitHub.
@@ -253,7 +252,7 @@ Python Packages
Playwright v1.57.1.dev0+g732639b35.d20251217
Browser
Active official/stable/135.0.1-beta.24
Browser v135.0.1-beta.24
Current browser v135.0.1-beta.24
Installed Yes
Latest in official/stable? Yes
Last Sync 2026-03-07 00:23
+42 -27
View File
@@ -226,7 +226,7 @@ def cli() -> None:
)
def sync(spoof_os, spoof_arch):
"""
Sync available versions from remote repositories.
Sync available versions from remote repositories
"""
if spoof_os == "auto":
spoof_os = None
@@ -239,7 +239,7 @@ def sync(spoof_os, spoof_arch):
@click.argument("version", default=None, required=False)
def fetch(version):
"""
Install the active version, or a specific version.
Install the active version, or a specific version
\b
Examples:
@@ -343,8 +343,6 @@ def _set_channel(repo_name: str, channel_type: str):
config = load_config()
config["channel"] = f"{repo_name}/{channel_type}"
config.pop("pinned", None)
save_config(config)
click.secho(f"Channel: {repo_name.lower()}/{channel_type}", fg="cyan", bold=True)
# Check if latest for this channel is already installed
is_pre = channel_type == "prerelease"
@@ -358,11 +356,18 @@ def _set_channel(repo_name: str, channel_type: str):
latest_build = candidates[0]["build"]
for inst in list_installed():
if inst.version.build == latest_build and inst.repo_name == repo_name.lower():
set_active(inst.relative_path)
config["active_version"] = inst.relative_path
save_config(config)
click.secho(
f"Channel: {repo_name.lower()}/{channel_type}", fg="cyan", bold=True
)
click.secho(f"Using latest: {inst.channel_path} (installed)", fg="green")
return
break
config.pop("active_version", None)
save_config(config)
click.secho(f"Channel: {repo_name.lower()}/{channel_type}", fg="cyan", bold=True)
click.secho("Run 'camoufox fetch' to install latest.", fg="yellow")
@@ -373,13 +378,15 @@ def _set_pinned(repo_name: str, channel_type: str, ver_data: dict, inst):
config = load_config()
config["channel"] = f"{repo_name}/{channel_type}"
config["pinned"] = f"{ver_data['version']}-{ver_data['build']}"
save_config(config)
ver_str = f"{ver_data['version']}-{ver_data['build']}"
display = f"{repo_name.lower()}/{channel_type}/{ver_str}"
if inst:
set_active(inst.relative_path)
config["active_version"] = inst.relative_path
save_config(config)
click.secho(f"Pinned: {display} (installed)", fg="green")
else:
config.pop("active_version", None)
save_config(config)
click.secho(f"Pinned: {display}", fg="cyan", bold=True)
click.secho("Run 'camoufox fetch' to install.", fg="yellow")
@@ -390,10 +397,13 @@ def _set_pinned(repo_name: str, channel_type: str, ver_data: dict, inst):
def set_cmd(specifier, geoip):
"""
\b
Interactive selector for versions and settings
Or, pass a specifier to activate directly:
Pin version: camoufox set official/stable/134.0.2-beta.20
Auto-update channel: camoufox set official/stable
Set the active Camoufox version to use & fetch.
By default, this opens an interactive selector for versions and settings.
You can also pass a specifier to activate directly:
Pin version:
camoufox set official/stable/134.0.2-beta.20
Automatically find latest in a channel source:
camoufox set official/stable
"""
if geoip:
_select_geoip_source()
@@ -704,10 +714,8 @@ def _list_all(_show_paths: bool):
def remove(version_path, select, yes):
"""
\b
Remove Camoufox data directory, or an installed browser version
Or, remove a specific version:
Select a version: camoufox remove --select
Remove a version: camoufox remove official/stable/134.0.2-beta.20
Remove downloaded data. By default, this removes everything.
Pass --select to pick a browser version to remove.
"""
import shutil
@@ -862,9 +870,9 @@ class VersionInfo:
# Browser version
if active_v:
self._row("Browser", f"v{active_v.version.full_string}")
self._row("Current browser", f"v{active_v.version.full_string}")
else:
self._row("Browser", "", style="dim")
self._row("Current browser", "Not installed", style="dim")
# Is installed?
if active_v:
@@ -927,7 +935,7 @@ class VersionInfo:
def _dir_size(self, path) -> str:
if not path.exists():
return ""
return "Nothing here"
total = sum(f.stat().st_size for f in path.rglob("*") if f.is_file())
for unit in ("B", "KB", "MB"):
if total < 1024:
@@ -968,21 +976,28 @@ def active_cmd():
"""
Print the current active version
"""
installed = list_installed()
for v in installed:
if v.is_active:
click.echo(v.channel_path)
return
config = load_config()
pinned = config.get("pinned")
channel = config.get("channel") or get_default_channel()
if pinned:
click.echo(f"{channel.lower()}/{pinned} ", nl=False)
rprint("(not installed)", fg="yellow")
# Check if the pinned version is installed
display = f"{channel.lower()}/{pinned}"
target = _find_installed(display)
if target:
click.echo(target.channel_path)
else:
click.echo(f"{display} ", nl=False)
rprint("(not fetched)", fg="yellow")
else:
# Using channel, so find active installed version
installed = list_installed()
for v in installed:
if v.is_active:
click.echo(v.channel_path)
return
click.echo(f"{channel.lower()} ", nl=False)
rprint("(not installed)", fg="yellow")
rprint("(not fetched)", fg="yellow")
@cli.command(name="path")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 28 KiB

+9 -6
View File
@@ -235,7 +235,8 @@ def list_installed() -> List[InstalledVersion]:
def get_active_path() -> Optional[Path]:
"""
Get path to active version. Auto-selects newest if none set
Get path to active version. Returns None if no version is active.
Only auto-selects if no channel/pin was been set
"""
config = load_config()
active = config.get('active_version')
@@ -245,11 +246,13 @@ def get_active_path() -> Optional[Path]:
if path.exists() and (path / 'version.json').exists():
return path
installed = list_installed()
if installed:
config['active_version'] = installed[0].relative_path
save_config(config)
return installed[0].path
# Only auto-select if user didnt set a channel or pin
if not config.get('channel') and not config.get('pinned'):
installed = list_installed()
if installed:
config['active_version'] = installed[0].relative_path
save_config(config)
return installed[0].path
return None
+21 -2
View File
@@ -647,7 +647,15 @@ def installed_verstr() -> str:
active = get_active_path()
if active is None:
raise FileNotFoundError("No active version. Please run `camoufox fetch` to install.")
from .multiversion import get_default_channel, load_config
config = load_config()
pinned = config.get("pinned")
channel = config.get("channel") or get_default_channel()
active_display = f"{channel}/{pinned}" if pinned else channel
raise CamoufoxNotInstalled(
f"{active_display} is not installed. " f"Please run `camoufox fetch` to install."
)
return Version.from_path(active).full_string
@@ -670,7 +678,18 @@ def camoufox_path(download_if_missing: bool = True) -> Path:
if not os.path.exists(INSTALL_DIR) or not os.listdir(INSTALL_DIR):
if not download_if_missing:
raise FileNotFoundError(f"Camoufox executable not found at {INSTALL_DIR}")
from .multiversion import load_config, get_default_channel
config = load_config()
pinned = config.get("pinned")
channel = config.get("channel") or get_default_channel()
if pinned:
active_display = f"{channel}/{pinned}"
else:
active_display = channel
raise CamoufoxNotInstalled(
f"{active_display} is not installed. " f"Please run `camoufox fetch` to install."
)
elif os.path.exists(INSTALL_DIR) and Version.from_path().is_supported():
return INSTALL_DIR