feat(browser): set_chrome_profile_appearance v1.1.0 — color tiñe el tema del navegador

Antes --color solo escribía los campos de color en Local State (info_cache), que
únicamente tiñen el círculo del avatar en el selector de perfiles. Ahora --color
aplica además el tema del navegador (toolbar, frame/bordes, barra de pestañas y
omnibox), que es lo que permite identificar un perfil de un vistazo.

El tema vive en el Preferences del perfil, no en Local State. La función ahora
escribe browser.theme.user_color2 (SkColor ARGB con signo), browser_color_variant
y is_grayscale2, y fuerza extensions.theme.system_theme=0. Escribe también las
claves legacy sin sufijo "2" por compatibilidad de versiones. Nuevo flag
--variant <0..4> (default 3 vibrant) para la intensidad del tinte. Backup y
validación del Preferences con el mismo patrón que Local State.

Claves verificadas empíricamente con captura de pantalla en Chromium 148: un
perfil lanzado con estas claves muestra la toolbar y el frame teñidos del color.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-06 10:12:37 +02:00
parent 25054ff64e
commit e2c073b8b7
2 changed files with 180 additions and 49 deletions
@@ -3,10 +3,10 @@ name: set_chrome_profile_appearance
kind: function
lang: bash
domain: browser
version: "1.0.0"
version: "1.1.0"
purity: impure
signature: "set_chrome_profile_appearance --user-data-dir <dir> --profile <dir-name> [--avatar <N|ruta.png>] [--color <#rrggbb>] [--dry-run]"
description: "Personaliza la apariencia visual de un perfil Chrome/Chromium existente: asigna un avatar built-in (índice 0..55) o una imagen PNG/JPG custom, y/o un color de acento (hex #rrggbb). Edita los campos avatar_icon, is_using_default_avatar, profile_highlight_color, profile_color_seed y default_avatar_fill_color en profile.info_cache de Local State. Requiere que Chromium esté cerrado sobre el user-data-dir. Hace backup de Local State antes de escribir y valida el JSON resultante."
signature: "set_chrome_profile_appearance --user-data-dir <dir> --profile <dir-name> [--avatar <N|ruta.png>] [--color <#rrggbb>] [--variant <0..4>] [--dry-run]"
description: "Personaliza la apariencia visual de un perfil Chrome/Chromium existente: asigna un avatar built-in (índice 0..55) o una imagen PNG/JPG custom, y/o un color de acento (hex #rrggbb). Con --color aplica el tinte tanto al círculo del avatar en Local State (profile_highlight_color, profile_color_seed, default_avatar_fill_color) como al tema completo del navegador en el Preferences del perfil (browser.theme.user_color2, browser_color_variant, extensions.theme.system_theme), tiñendo toolbar, frame, barra de pestañas y omnibox. Requiere que Chromium esté cerrado sobre el user-data-dir. Hace backup de Local State y Preferences antes de escribir y valida el JSON resultante."
tags: [navegator, chromium, profile, browser, cdp, scraping, appearance, avatar, color]
uses_functions: []
uses_types: []
@@ -26,10 +26,12 @@ params:
- name: --avatar
desc: "Índice entero 0..55 del avatar built-in de Chrome (56 avatares: animales, objetos, personas) o ruta absoluta/relativa a un archivo PNG/JPG para avatar custom. Con índice: sets avatar_icon=IDR_PROFILE_AVATAR_<N> e is_using_default_avatar=true. Con imagen: copia el archivo al perfil como 'Google Profile Picture.png' y sets is_using_default_avatar=false. Opcional; al menos uno de --avatar o --color debe darse."
- name: --color
desc: "Color de acento del perfil en hex #rrggbb, con o sin el '#' inicial. Se convierte internamente a int32 con signo en formato ARGB 0xFFRRGGBB y se aplica a profile_highlight_color, profile_color_seed y default_avatar_fill_color. Opcional; al menos uno de --avatar o --color debe darse."
desc: "Color de acento del perfil en hex #rrggbb, con o sin el '#' inicial. Se convierte a int32 con signo en formato ARGB 0xFFRRGGBB. Aplica el color en dos lugares: (1) Local State info_cache (profile_highlight_color, profile_color_seed, default_avatar_fill_color) para el círculo del avatar; (2) Preferences del perfil (browser.theme.user_color2 + browser_color_variant + extensions.theme.system_theme=0) para teñir toolbar, frame, barra de pestañas y omnibox. Opcional; al menos uno de --avatar o --color debe darse."
- name: --variant
desc: "Intensidad del tema de color aplicado al navegador (browser_color_variant). Entero 0..4: 0=system, 1=tonal_spot, 2=neutral, 3=vibrant (default), 4=expressive. Valores más altos dan tintes más saturados e identificables. Solo tiene efecto cuando se usa --color. Opcional."
- name: --dry-run
desc: "Describe las acciones que se ejecutarían (campos a modificar, conversión de color) sin escribir nada ni verificar si Chromium está corriendo. Emite JSON de resultado con dry_run:true."
output: "JSON en stdout con los campos resultantes del perfil: {\"profile\":\"<dir>\",\"avatar_icon\":\"...\",\"is_using_default_avatar\":true|false,\"profile_highlight_color\":<int>,\"profile_color_seed\":<int>,\"default_avatar_fill_color\":<int>,\"backup\":\"Local State.bak.YYYYMMDD\"}. En dry-run: {\"profile\":\"...\",\"avatar_applied\":true|false,\"color_applied\":true|false,\"dry_run\":true}. Mensajes de diagnóstico a stderr. Exit 0 en éxito."
desc: "Describe las acciones que se ejecutarían (campos a modificar en Local State y Preferences, conversión de color, ruta del Preferences) sin escribir nada ni verificar si Chromium está corriendo. Emite JSON de resultado con dry_run:true."
output: "JSON en stdout con los campos resultantes del perfil: {\"profile\":\"<dir>\",\"avatar_icon\":\"...\",\"is_using_default_avatar\":true|false,\"profile_highlight_color\":<int>,\"profile_color_seed\":<int>,\"default_avatar_fill_color\":<int>,\"theme_applied\":true|false,\"variant\":<int>,\"preferences_path\":\"...\",\"browser_theme_user_color2\":<int>,\"browser_theme_color_variant\":<int>,\"extensions_theme_system_theme\":<int>,\"backup\":\"Local State.bak.YYYYMMDD\"}. En dry-run: {\"profile\":\"...\",\"avatar_applied\":true|false,\"color_applied\":true|false,\"theme_applied\":true|false,\"variant\":<int>,\"dry_run\":true}. Mensajes de diagnóstico a stderr. Exit 0 en éxito."
---
## Ejemplo
@@ -37,54 +39,51 @@ output: "JSON en stdout con los campos resultantes del perfil: {\"profile\":\"<d
```bash
source $HOME/fn_registry/bash/functions/browser/set_chrome_profile_appearance.sh
# Asignar avatar built-in #26 (oso panda) y color azul GitHub al perfil Automation
# Asignar avatar #30 y tinte verde a toolbar/frame/omnibox del perfil Automation
# (verde #16a34a tiñe toda la chrome del navegador, no solo el círculo del avatar)
set_chrome_profile_appearance \
--user-data-dir ~/.config/chromium-cdp \
--profile Automation \
--avatar 26 \
--color "#1f6feb"
# Salida JSON con los valores aplicados
--avatar 30 \
--color "#16a34a"
# Salida JSON incluye: theme_applied:true, variant:3, browser_theme_user_color2:-15293622
# Solo cambiar color (sin tocar avatar)
# Color con intensidad personalizada (expressive = máxima saturación)
set_chrome_profile_appearance \
--user-data-dir ~/.config/chromium-cdp \
--profile Default \
--color "16a34a"
--profile Scraping \
--color "#1f6feb" \
--variant 4
# Solo cambiar avatar built-in
# Solo cambiar avatar (no toca Preferences del perfil)
set_chrome_profile_appearance \
--user-data-dir ~/.config/chromium-cdp \
--profile "Profile 1" \
--avatar 5
# Avatar custom desde imagen
set_chrome_profile_appearance \
--user-data-dir ~/.config/chromium-cdp \
--profile Personal \
--avatar /tmp/foto.png \
--color "#0ea5e9"
# Dry-run: ver qué se aplicaría sin escribir
# Dry-run: ver qué se aplicaría en Local State y Preferences sin escribir
set_chrome_profile_appearance \
--user-data-dir ~/.config/chromium-cdp \
--profile Automation \
--avatar 26 \
--color "#1f6feb" \
--avatar 30 \
--color "#16a34a" \
--dry-run
```
## Cuando usarla
Úsala para diferenciar visualmente los perfiles de un user-data-dir de automatización — un color y avatar distintos por perfil hacen inmediata la identificación en el selector de Chrome. Ejecútala justo después de `create_chrome_profile` (con `--no-launch`) o como paso independiente de personalización batch antes de lanzar sesiones CDP.
Úsala para diferenciar visualmente los perfiles de un user-data-dir de automatización — un color y avatar distintos por perfil hacen inmediata la identificación en el selector de Chrome Y en la chrome del navegador (toolbar/frame visible mientras navega). Ejecútala justo después de `create_chrome_profile` (con `--no-launch`) o como paso independiente de personalización batch antes de lanzar sesiones CDP. Si solo quieres teñir el círculo del avatar (sin el tema), basta esta función; si quieres el tinte completo del navegador (lo más identificable), pasa `--color`.
## Gotchas
- **Chromium debe estar cerrado**: Chrome reescribe `Local State` completo desde memoria al cerrar; si se ejecuta mientras hay un proceso chromium vivo sobre el mismo user-data-dir, Chrome sobreescribirá los cambios al salir. La función detecta esto con `pgrep -x chromium` filtrando por cmdline y sale con exit 2 antes de modificar nada. Usa `pkill -TERM chromium` para cerrar y espera unos segundos.
- **Chromium debe estar cerrado**: Chrome reescribe `Local State` y `Preferences` completos desde memoria al cerrar; si se ejecuta mientras hay un proceso chromium vivo sobre el mismo user-data-dir, Chrome sobreescribirá los cambios al salir. La función detecta esto con `pgrep -x chromium` filtrando por cmdline y sale con exit 2 antes de modificar nada. Usa `pkill -TERM chromium` para cerrar y espera unos segundos.
- **El tema se escribe en Preferences del perfil, distinto de Local State**: los cambios de color al avatar van en `<user-data-dir>/Local State` (global a todos los perfiles); los cambios de tema del navegador van en `<user-data-dir>/<profile_dir>/Preferences` (específico de cada perfil). La función hace backup de ambos archivos por separado antes de tocarlos.
- **El perfil debe existir en info_cache**: esta función personaliza perfiles existentes; no los crea. Usa `create_chrome_profile` primero (con `--no-launch` basta para que aparezca en Local State) y luego `set_chrome_profile_appearance`.
- **color es int32 con signo en ARGB**: Chrome almacena el color como entero con signo de 32 bits en formato `0xAARRGGBB`. Un color como `#1f6feb` (azul) da ARGB `0xFF1F6FEB` → signed int32 `-14713877`. La función hace la conversión internamente; tú pasas siempre hex `#rrggbb`.
- **color es int32 con signo en ARGB**: Chrome almacena el color como entero con signo de 32 bits en formato `0xAARRGGBB`. Un color como `#16a34a` (verde) da ARGB `0xFF16A34A` → signed int32 `-15293622`. La función hace la conversión internamente; tú pasas siempre hex `#rrggbb`.
- **En modo oscuro del sistema el tinte sale más apagado**: en temas oscuros del sistema el color se mezcla con el fondo oscuro y queda menos saturado. Para compensar, usa `--variant 3` (vibrant, default) o `--variant 4` (expressive); valores bajos como 1 o 2 pueden resultar casi imperceptibles en modo oscuro.
- **`extensions.theme.system_theme` se fuerza a 0**: si el perfil usaba el tema GTK del sistema (`system_theme=1`), el GTK puede ignorar el `user_color`. Esta función lo fuerza a 0 (tema propio de Chrome) para que el `user_color2` tenga efecto. Si quieres devolver el perfil al tema del sistema, tendrás que resetear `system_theme` manualmente.
- **Avatar custom (imagen) es best-effort**: el campo `gaia_picture_file_name` y `is_using_default_avatar=false` se aplican correctamente en Local State y la imagen se copia al directorio del perfil. Sin embargo, Chrome puede ignorar la foto de perfil en perfiles sin sesión Google activa (Chromium sin cuenta). El camino robusto y garantizado es usar el índice built-in (`--avatar 0..55`): 56 avatares (animales, objetos, personas) son más que suficientes para diferenciar perfiles de automatización.
- **Backup diario**: se crea `Local State.bak.YYYYMMDD` en el user-data-dir antes de cualquier escritura. Si ya existe el backup del día no se sobreescribe. Si el JSON resultante es inválido, se restaura automáticamente el backup.
- **is_using_default_avatar con índice built-in**: Chrome considera los avatares IDR_PROFILE_AVATAR_* como "avatares por defecto" del sistema, por eso `is_using_default_avatar` permanece `true` con índice numérico. Esto es correcto y es lo que Chrome haría internamente.
- **Backup diario**: se crea `Local State.bak.YYYYMMDD` y `Preferences.bak.YYYYMMDD` antes de cualquier escritura. Si ya existen los backups del día no se sobreescriben. Si el JSON resultante es inválido, se restaura automáticamente el backup correspondiente.
## Exit codes
@@ -94,4 +93,8 @@ set_chrome_profile_appearance \
| 1 | Argumento obligatorio faltante, rango inválido o archivo de imagen no encontrado |
| 2 | Lock: hay un chromium usando el mismo user-data-dir |
| 3 | El perfil no existe en info_cache de Local State |
| 4 | Error editando Local State (JSON inválido tras escritura, restaurado backup) |
| 4 | Error editando Local State o Preferences (JSON inválido tras escritura, restaurado backup) |
## Capability growth log
v1.1.0 (2026-06-06) — --color ahora aplica también el tema del navegador (toolbar/frame/omnibox) escribiendo browser.theme.user_color2 + browser_color_variant en el Preferences del perfil, no solo el color del avatar en Local State. Nuevo flag --variant (0..4, default 3 vibrant). Verificado con captura en Chromium 148.