# jlauncher

Lanzador de juegos de **jailgames**. A partir de `games.toml`, lista los juegos, los
clona/actualiza desde sus repos Gitea, lee su icono y descripción, y los compila/ejecuta.

GUI en **Python + PySide6**, pensada para compilarse a binario nativo con **Nuitka**.

## Requisitos

- Python 3.11+ (usa `tomllib` de la stdlib)
- `git` en el PATH
- `pip install PySide6`

## Ejecutar desde fuente

```bash
pip install PySide6
python -m jlauncher
```

La app crea una carpeta `jlauncher_data/` junto al proyecto (o junto al binario, si está
compilado) con esta estructura **anidada (Versión 1)**:

```
jlauncher_data/
  <id_juego>/
    repo/          # git clone del juego
    metadata/
      info.json    # descripción, versión, rama por defecto, fecha de actualización
      icon.png     # copiado desde repo/release/icons/icon.png
```

## Botones (interfaz en catalán)

- **Descarrega**: si no existe el clone, hace `git clone`. Si existe, trae el remoto
  **forzado** (`git fetch` + `git reset --hard origin/<rama>` + `git clean -fd`),
  descartando cualquier cambio local. Después refresca la metadata:
  - descripción desde la API de Gitea (`/api/v1/repos/<org>/<repo>`),
  - versión ejecutando `version_cmd` (por defecto `git describe --tags --always`),
  - icono desde `release/icons/icon.png`.
- **Juga**: si hay `build_cmd`, compila primero; luego ejecuta `run_cmd`. Para estos
  juegos basta `run_cmd = "make run"` (compila y ejecuta), con `build_cmd` vacío.
- **Esborra**: elimina la descarga local (carpeta del juego en `jlauncher_data/`),
  sin quitar el juego del `games.toml`.

Menú **Opcions**: *Amaga els jocs no descarregats* (filtro persistente) y
*Comprova actualitzacions* (marca los juegos descargados con commits pendientes).
Las preferencias se guardan en `settings.json` junto al ejecutable.

Las operaciones corren en segundo plano (QThreadPool); el log aparece en el panel inferior.

## Configuración: `games.toml`

Una entrada `[[game]]` por juego. Campos:

| Campo         | Obligatorio | Descripción                                                        |
|---------------|-------------|--------------------------------------------------------------------|
| `id`          | sí          | slug → nombre de carpeta en `jlauncher_data/`                       |
| `name`        | sí          | nombre visible                                                      |
| `clone_url`   | sí          | URL de git clone / pull                                             |
| `run_cmd`     | sí          | comando que ejecuta el juego (cwd = repo)                           |
| `build_cmd`   | no          | comando de compilado; vacío = `run_cmd` ya compila                  |
| `version_cmd` | no          | comando que imprime la versión (def. `git describe --tags --always`)|
| `info_url`    | no          | API Gitea del repo (def. derivada de `clone_url`)                  |
| `icon_rel`    | no          | ruta del icono dentro del repo (def. `release/icons/icon.png`)     |

## Compilar a binario (Nuitka, onefile)

`build.sh` lo hace todo: crea el `.venv`, instala dependencias (PySide6 + Nuitka +
zstandard) y compila un único ejecutable comprimido, empaquetándolo en
`dist/jlauncher-v<versión>-<os>-<arch>.tar.gz` junto a `games.toml`.

```bash
./build.sh
# binario: dist/jlauncher  (+ dist/games.toml)
```

El binario crea `jlauncher_data/` y `settings.json` **junto a sí mismo** (resuelto vía
`NUITKA_ONEFILE_DIRECTORY`). El punto de entrada para empaquetar es `app.py` (desde
fuente se ejecuta con `python -m jlauncher`).

### Prerequisitos del sistema (no los instala el script)

- **Python 3.11+** (usa `tomllib`).
- Un **compilador C**:
  - Linux: `gcc` y `patchelf` (p. ej. `apt install build-essential patchelf python3-dev`).
  - macOS: **Xcode Command Line Tools** (`xcode-select --install`); aquí *no* hace falta
    patchelf (Nuitka usa `install_name_tool`).
- `git` en el PATH.

### macOS (.app + .dmg)

Compila en el propio Mac (Nuitka no compila cruzado). En macOS, `./build.sh` no genera un
binario suelto sino una **app nativa**:

```bash
./build.sh
# -> dist/jlauncher.app
# -> dist/jlauncher-v<versión>-macos-<arch>.dmg   (arrastrar la app a Aplicaciones)
```

El icono vive en `icon/`: el build usa `icon/icon.icns` para el bundle y copia
`icon/icon.png` (1024×1024) dentro del `.app` para el diálogo «Quant a». Para cambiarlo,
sustituye esos ficheros (regenerables con `icon/create_icons.py`).

A diferencia del onefile, la `.app` **no** escribe junto a sí misma (rompería al moverla a
`/Applications`): guarda sus datos en
`~/Library/Application Support/jailgames/jlauncher/` (`jlauncher_data/`, `settings.json` y
una copia editable de `games.toml`, sembrada la primera vez desde el bundle).

La app va **sin firma Developer ID** (firma ad-hoc), así que Gatekeeper avisará la primera
vez: ábrela con **clic derecho → Abrir**, o ejecuta
`xattr -dr com.apple.quarantine /Applications/jlauncher.app`.
