Modo portatil: ejecutar FOSFENO en un portatil Linux
Anade 'bash install.sh --laptop' y el lanzador './fosfeno' para correr FOSFENO en portatiles Debian/Ubuntu/Mint sin Raspberry Pi: puerto 8080, sin arranque automatico ni cambios en el sistema. El servidor admite las variables FOSFENO_PORT y FOSFENO_NO_KIOSK. Nueva documentacion en docs/portatil.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
30a09fdee6
commit
3c1c631895
7 changed files with 250 additions and 53 deletions
|
|
@ -76,6 +76,12 @@ bash install.sh --no-projectm # omite la compilación de projectM
|
|||
bash install.sh --check # solo comprueba el sistema, no instala nada
|
||||
```
|
||||
|
||||
### En un portátil Linux
|
||||
|
||||
FOSFENO también corre en un portátil con Debian, Ubuntu o Mint, sin Raspberry
|
||||
Pi. Se instala con `bash install.sh --laptop` y se arranca cuando quieras con
|
||||
`./fosfeno`. Los detalles están en [FOSFENO en un portátil](docs/portatil.md).
|
||||
|
||||
Después:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Motores: projectm (nativo), butterchurn, hydra, shaders (GLSL) y mixer
|
|||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
|
|
@ -44,7 +45,10 @@ def load_json(path, default):
|
|||
|
||||
CFG = load_json(BASE / "config.json", {})
|
||||
HOST = CFG.get("server", {}).get("host", "0.0.0.0")
|
||||
PORT = int(CFG.get("server", {}).get("port", 80))
|
||||
# El puerto y el modo kiosko se pueden forzar por variable de entorno; asi el
|
||||
# modo portatil (script 'fosfeno') usa el puerto 8080 sin tocar config.json.
|
||||
PORT = int(os.environ.get("FOSFENO_PORT") or CFG.get("server", {}).get("port", 80))
|
||||
NO_KIOSK = bool(os.environ.get("FOSFENO_NO_KIOSK"))
|
||||
|
||||
app = Flask(__name__, static_folder=None)
|
||||
socketio = SocketIO(app, async_mode="threading", cors_allowed_origins="*")
|
||||
|
|
@ -180,7 +184,7 @@ def start_chromium():
|
|||
notify("error", "No se encontro Chromium. Las visuales web no pueden "
|
||||
"mostrarse. Ejecuta install.sh para instalarlo.")
|
||||
return
|
||||
url = kiosk.get("url", f"http://localhost:{PORT}/stage")
|
||||
url = f"http://localhost:{PORT}/stage"
|
||||
procs["chromium"] = subprocess.Popen([
|
||||
browser,
|
||||
"--kiosk", f"--app={url}",
|
||||
|
|
@ -442,7 +446,8 @@ def watchdog():
|
|||
time.sleep(10)
|
||||
if refresh_network():
|
||||
broadcast()
|
||||
if state["engine"] != "projectm" and not is_running(procs["chromium"]):
|
||||
if not NO_KIOSK and state["engine"] != "projectm" \
|
||||
and not is_running(procs["chromium"]):
|
||||
notify("warn", "El navegador de las visuales se cerro. "
|
||||
"Reabriendolo automaticamente.")
|
||||
start_chromium()
|
||||
|
|
@ -471,7 +476,9 @@ def main():
|
|||
check_install()
|
||||
setup_audio()
|
||||
refresh_network()
|
||||
threading.Timer(3.0, start_chromium).start()
|
||||
# En modo portatil el script 'fosfeno' abre el navegador; el servidor no.
|
||||
if not NO_KIOSK:
|
||||
threading.Timer(3.0, start_chromium).start()
|
||||
threading.Thread(target=watchdog, daemon=True).start()
|
||||
|
||||
net = state["network"]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
"port": 80
|
||||
},
|
||||
"kiosk": {
|
||||
"url": "http://localhost/stage",
|
||||
"browser": "chromium-browser"
|
||||
},
|
||||
"audio": {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ para consultarse a saltos después.
|
|||
Cómo encuentra el usuario el panel de control: el código QR del proyector,
|
||||
la dirección `fosfeno.local` y qué hacer con el router.
|
||||
|
||||
- [FOSFENO en un portátil Linux](portatil.md)
|
||||
Cómo correr FOSFENO en un portátil Debian, Ubuntu o Mint, sin Raspberry Pi.
|
||||
|
||||
- [Uso del panel](uso.md)
|
||||
Cómo se maneja desde el móvil, qué hace cada motor de visuales y cómo se
|
||||
configura cada opción.
|
||||
|
|
|
|||
71
docs/portatil.md
Normal file
71
docs/portatil.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# FOSFENO en un portátil Linux
|
||||
|
||||
FOSFENO nació para una Raspberry Pi, pero está hecho con tecnología web, así
|
||||
que funciona igual de bien en un portátil con Linux. De hecho un portátil va
|
||||
más sobrado, ya trae micrófono y cámara, y lo conectas al proyector por HDMI
|
||||
como cualquier otra cosa.
|
||||
|
||||
Este modo está pensado para Debian, Ubuntu o Linux Mint, que son las
|
||||
distribuciones que usan `apt`.
|
||||
|
||||
## Instalar
|
||||
|
||||
Una sola vez, desde la carpeta del proyecto:
|
||||
|
||||
```
|
||||
bash install.sh --laptop
|
||||
```
|
||||
|
||||
Hace lo mismo que en la Raspberry (entorno de Python, librerías de visuales,
|
||||
y projectM si quieres), pero sin las cosas propias de un aparato dedicado: no
|
||||
toca el arranque del sistema, no cambia el nombre de red y no necesita
|
||||
permisos especiales de puertos.
|
||||
|
||||
## Arrancar
|
||||
|
||||
Cuando quieras usarlo, desde la carpeta del proyecto:
|
||||
|
||||
```
|
||||
./fosfeno
|
||||
```
|
||||
|
||||
Eso levanta FOSFENO y abre dos cosas:
|
||||
|
||||
- El **panel de control** en tu navegador, en `http://localhost:8080/`.
|
||||
- Una **ventana con las visuales**, aparte.
|
||||
|
||||
Para cerrarlo todo, pulsa `Ctrl+C` en la terminal donde lanzaste `./fosfeno`.
|
||||
|
||||
## Llevar las visuales al proyector
|
||||
|
||||
La ventana de las visuales es una ventana normal. Conecta el proyector por
|
||||
HDMI, arrastra esa ventana a la pantalla del proyector y pulsa `F11` para
|
||||
ponerla a pantalla completa. El panel de control lo manejas desde el portátil,
|
||||
o desde el móvil si prefieres.
|
||||
|
||||
## Micrófono y cámara
|
||||
|
||||
El portátil ya trae micrófono y cámara integrados. No hace falta nada por USB,
|
||||
aunque puedes usarlo si quieres mejor sonido o una webcam mejor.
|
||||
|
||||
La primera vez, elige el micrófono en el apartado Audio del panel, y la cámara
|
||||
en el apartado del Mezclador. Si los conectas con FOSFENO ya abierto, usa el
|
||||
botón de buscar dispositivos de nuevo.
|
||||
|
||||
## Controlarlo desde el móvil
|
||||
|
||||
Si quieres manejar el panel desde el móvil mientras el portátil hace de VJ,
|
||||
conecta el móvil a la misma red WiFi y entra en `http://nombre-del-portatil.local:8080/`.
|
||||
El nombre del portátil lo ves con el comando `hostname`. La dirección exacta
|
||||
también aparece en la terminal al arrancar `./fosfeno`.
|
||||
|
||||
## En qué se diferencia de la Raspberry
|
||||
|
||||
- No arranca solo: lo lanzas tú con `./fosfeno` cuando lo necesitas.
|
||||
- Usa el puerto 8080 en lugar del 80.
|
||||
- No cambia el nombre de red del equipo.
|
||||
- Los botones de reiniciar y apagar del panel no harán nada (es tu portátil,
|
||||
no un aparato dedicado, así que es lo correcto).
|
||||
|
||||
Todo lo demás (los cinco motores, el editor de código, la detección de BPM,
|
||||
el mezclador) funciona exactamente igual.
|
||||
77
fosfeno
Executable file
77
fosfeno
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env bash
|
||||
# ===========================================================================
|
||||
# FOSFENO :: arranque en modo portatil (Linux de escritorio)
|
||||
#
|
||||
# Lanza el servidor, abre el panel y las visuales, y lo cierra todo con Ctrl+C.
|
||||
# Antes hay que instalar una vez con: bash install.sh --laptop
|
||||
# ===========================================================================
|
||||
set -u
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PORT=8080
|
||||
export FOSFENO_PORT="$PORT"
|
||||
export FOSFENO_NO_KIOSK=1
|
||||
|
||||
if [ ! -x "$DIR/.venv/bin/python3" ]; then
|
||||
echo "FOSFENO no esta instalado todavia. Ejecuta primero:"
|
||||
echo " bash install.sh --laptop"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SERVER_PID=""
|
||||
STAGE_PID=""
|
||||
cleanup() {
|
||||
echo
|
||||
echo "Cerrando FOSFENO..."
|
||||
[ -n "$STAGE_PID" ] && kill "$STAGE_PID" 2>/dev/null
|
||||
[ -n "$SERVER_PID" ] && kill "$SERVER_PID" 2>/dev/null
|
||||
exit 0
|
||||
}
|
||||
trap cleanup INT TERM
|
||||
|
||||
echo "Arrancando FOSFENO..."
|
||||
"$DIR/.venv/bin/python3" "$DIR/backend/server.py" &
|
||||
SERVER_PID=$!
|
||||
|
||||
# Espera (hasta 20 s) a que el servidor responda
|
||||
for _ in $(seq 1 40); do
|
||||
curl -s "http://localhost:$PORT/" >/dev/null 2>&1 && break
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
# Abre las visuales en una ventana propia de Chromium. Es una ventana normal:
|
||||
# arrastrala al proyector y pulsa F11 para ponerla a pantalla completa.
|
||||
BROWSER="$(command -v chromium-browser || command -v chromium \
|
||||
|| command -v google-chrome || true)"
|
||||
if [ -n "$BROWSER" ]; then
|
||||
"$BROWSER" --app="http://localhost:$PORT/stage" \
|
||||
--user-data-dir="/tmp/fosfeno-stage" \
|
||||
--use-fake-ui-for-media-stream \
|
||||
--autoplay-policy=no-user-gesture-required \
|
||||
>/dev/null 2>&1 &
|
||||
STAGE_PID=$!
|
||||
else
|
||||
echo "Aviso: no se encontro Chromium. Abre las visuales a mano en:"
|
||||
echo " http://localhost:$PORT/stage"
|
||||
fi
|
||||
|
||||
# Abre el panel de control en el navegador por defecto
|
||||
xdg-open "http://localhost:$PORT/" >/dev/null 2>&1 || true
|
||||
|
||||
cat <<EOF
|
||||
|
||||
FOSFENO en marcha (modo portatil).
|
||||
|
||||
Panel de control: http://localhost:$PORT/
|
||||
Visuales: ventana de Chromium aparte
|
||||
(arrastrala al proyector y pulsa F11)
|
||||
|
||||
Desde el movil, en la misma red WiFi:
|
||||
http://$(hostname).local:$PORT/
|
||||
|
||||
Pulsa Ctrl+C aqui para cerrar FOSFENO.
|
||||
|
||||
EOF
|
||||
|
||||
wait "$SERVER_PID"
|
||||
cleanup
|
||||
130
install.sh
130
install.sh
|
|
@ -2,7 +2,8 @@
|
|||
# ===========================================================================
|
||||
# FOSFENO :: instalador para Raspberry Pi OS Bookworm (Raspberry Pi 4 y 5)
|
||||
#
|
||||
# Uso: bash install.sh # instala todo (incluido projectM)
|
||||
# Uso: bash install.sh # Raspberry Pi: instala todo
|
||||
# bash install.sh --laptop # portatil Linux (Debian/Ubuntu/Mint)
|
||||
# bash install.sh --no-projectm # omite la compilacion de projectM
|
||||
# bash install.sh --check # solo comprueba el sistema, no instala
|
||||
# ===========================================================================
|
||||
|
|
@ -13,10 +14,12 @@ source "$DIR/scripts/lib.sh"
|
|||
|
||||
MODE="install"
|
||||
SKIP_PM="no"
|
||||
LAPTOP="no"
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-projectm) SKIP_PM="yes" ;;
|
||||
--check) MODE="check" ;;
|
||||
--laptop) LAPTOP="yes" ;;
|
||||
*) echo "Opcion desconocida: $arg"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
|
@ -34,32 +37,34 @@ printf '%s\n' "===================================================$C_RST"
|
|||
# ---------------------------------------------------------------------------
|
||||
# 1. Comprobacion del hardware y del sistema operativo
|
||||
# ---------------------------------------------------------------------------
|
||||
log_step "[1/9] Comprobando hardware y sistema operativo"
|
||||
|
||||
MODELO="$(pi_model)"
|
||||
log_info "Modelo detectado: $MODELO"
|
||||
case "$MODELO" in
|
||||
*"Raspberry Pi 5"*) log_ok "Raspberry Pi 5 (soportada)" ;;
|
||||
*"Raspberry Pi 4"*) log_ok "Raspberry Pi 4 (soportada)" ;;
|
||||
*"Raspberry Pi"*) warn "Raspberry Pi distinta de 4/5: puede funcionar pero sin garantias" ;;
|
||||
*) warn "No parece una Raspberry Pi: continuando bajo tu responsabilidad" ;;
|
||||
esac
|
||||
log_step "[1/9] Comprobando el sistema"
|
||||
|
||||
if [ -r /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
log_info "Sistema: ${PRETTY_NAME:-desconocido}"
|
||||
if [ "${VERSION_CODENAME:-}" = "bookworm" ]; then
|
||||
log_ok "Raspberry Pi OS Bookworm"
|
||||
else
|
||||
fi
|
||||
|
||||
if [ "$LAPTOP" = "yes" ]; then
|
||||
log_ok "Modo portatil (Linux de escritorio)"
|
||||
if ! need_cmd apt-get; then
|
||||
log_fail "El modo --laptop usa apt (Debian, Ubuntu o Mint)."
|
||||
log_fail "Tu sistema no tiene apt; este instalador no sirve aqui."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
MODELO="$(pi_model)"
|
||||
log_info "Modelo detectado: $MODELO"
|
||||
case "$MODELO" in
|
||||
*"Raspberry Pi 5"*) log_ok "Raspberry Pi 5 (soportada)" ;;
|
||||
*"Raspberry Pi 4"*) log_ok "Raspberry Pi 4 (soportada)" ;;
|
||||
*"Raspberry Pi"*) warn "Raspberry Pi distinta de 4/5: puede funcionar pero sin garantias" ;;
|
||||
*) warn "No parece una Raspberry Pi. Si es un portatil, usa: bash install.sh --laptop" ;;
|
||||
esac
|
||||
if [ "${VERSION_CODENAME:-}" != "bookworm" ]; then
|
||||
warn "Se recomienda Raspberry Pi OS Bookworm (detectado: ${VERSION_CODENAME:-?})"
|
||||
fi
|
||||
fi
|
||||
|
||||
ARCH="$(uname -m)"
|
||||
log_info "Arquitectura: $ARCH"
|
||||
[ "$ARCH" = "aarch64" ] && log_ok "Sistema de 64 bits" \
|
||||
|| warn "Se recomienda Raspberry Pi OS de 64 bits para mejor rendimiento"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Modo --check: solo verifica lo que ya esta instalado y termina
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -222,43 +227,55 @@ log_info "Copia tus clips .mp4 en: $DIR/data/videos/"
|
|||
# ---------------------------------------------------------------------------
|
||||
# 8. Arranque automatico y permisos
|
||||
# ---------------------------------------------------------------------------
|
||||
log_step "[8/9] Configurando arranque automatico y permisos"
|
||||
chmod +x "$DIR/scripts/"*.sh "$DIR/install.sh" "$DIR/uninstall.sh"
|
||||
mkdir -p "$HOME/.config/autostart"
|
||||
if sed "s#__DIR__#$DIR#g" "$DIR/scripts/fosfeno-autostart.desktop" \
|
||||
> "$HOME/.config/autostart/fosfeno.desktop"; then
|
||||
log_ok "Arranque automatico configurado (~/.config/autostart/fosfeno.desktop)"
|
||||
fi
|
||||
log_step "[8/9] Arranque automatico y permisos"
|
||||
chmod +x "$DIR/scripts/"*.sh "$DIR/install.sh" "$DIR/uninstall.sh" 2>/dev/null
|
||||
[ -f "$DIR/fosfeno" ] && chmod +x "$DIR/fosfeno"
|
||||
|
||||
# Nombre de red fijo: deja el panel accesible en http://<hostname>.local/
|
||||
HOSTNAME_WANT="$(python3 -c "import json;print(json.load(open('$DIR/config.json')).get('network',{}).get('hostname','fosfeno'))" 2>/dev/null || echo fosfeno)"
|
||||
if [ "$(hostname)" != "$HOSTNAME_WANT" ]; then
|
||||
sudo hostnamectl set-hostname "$HOSTNAME_WANT" 2>/dev/null || true
|
||||
if grep -q "^127.0.1.1" /etc/hosts; then
|
||||
sudo sed -i "s/^127.0.1.1.*/127.0.1.1\t$HOSTNAME_WANT/" /etc/hosts
|
||||
else
|
||||
echo -e "127.0.1.1\t$HOSTNAME_WANT" | sudo tee -a /etc/hosts >/dev/null
|
||||
HOSTNAME_WANT="$(hostname)"
|
||||
if [ "$LAPTOP" = "yes" ]; then
|
||||
log_info "Modo portatil: sin arranque automatico ni cambios en el sistema."
|
||||
log_info "FOSFENO se lanza a mano con ./fosfeno cuando quieras usarlo."
|
||||
else
|
||||
mkdir -p "$HOME/.config/autostart"
|
||||
if sed "s#__DIR__#$DIR#g" "$DIR/scripts/fosfeno-autostart.desktop" \
|
||||
> "$HOME/.config/autostart/fosfeno.desktop"; then
|
||||
log_ok "Arranque automatico configurado (~/.config/autostart/fosfeno.desktop)"
|
||||
fi
|
||||
log_ok "Nombre de red puesto a '$HOSTNAME_WANT' (panel en http://$HOSTNAME_WANT.local/)"
|
||||
else
|
||||
log_ok "Nombre de red: $HOSTNAME_WANT"
|
||||
fi
|
||||
|
||||
if echo "$USER ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/poweroff" \
|
||||
| sudo tee /etc/sudoers.d/fosfeno >/dev/null \
|
||||
&& sudo chmod 440 /etc/sudoers.d/fosfeno; then
|
||||
log_ok "Permisos de reinicio/apagado configurados"
|
||||
# Nombre de red fijo: deja el panel accesible en http://<hostname>.local/
|
||||
HOSTNAME_WANT="$(python3 -c "import json;print(json.load(open('$DIR/config.json')).get('network',{}).get('hostname','fosfeno'))" 2>/dev/null || echo fosfeno)"
|
||||
if [ "$(hostname)" != "$HOSTNAME_WANT" ]; then
|
||||
sudo hostnamectl set-hostname "$HOSTNAME_WANT" 2>/dev/null || true
|
||||
if grep -q "^127.0.1.1" /etc/hosts; then
|
||||
sudo sed -i "s/^127.0.1.1.*/127.0.1.1\t$HOSTNAME_WANT/" /etc/hosts
|
||||
else
|
||||
echo -e "127.0.1.1\t$HOSTNAME_WANT" | sudo tee -a /etc/hosts >/dev/null
|
||||
fi
|
||||
log_ok "Nombre de red puesto a '$HOSTNAME_WANT' (panel en http://$HOSTNAME_WANT.local/)"
|
||||
else
|
||||
log_ok "Nombre de red: $HOSTNAME_WANT"
|
||||
fi
|
||||
|
||||
if echo "$USER ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/poweroff" \
|
||||
| sudo tee /etc/sudoers.d/fosfeno >/dev/null \
|
||||
&& sudo chmod 440 /etc/sudoers.d/fosfeno; then
|
||||
log_ok "Permisos de reinicio/apagado configurados"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 9. Permiso para el puerto 80
|
||||
# 9. Acceso de red
|
||||
# ---------------------------------------------------------------------------
|
||||
log_step "[9/9] Permitiendo a Python escuchar en el puerto 80"
|
||||
PYBIN="$(readlink -f "$DIR/.venv/bin/python3")"
|
||||
if sudo setcap 'cap_net_bind_service=+ep' "$PYBIN" 2>/dev/null; then
|
||||
log_ok "Puerto 80 habilitado"
|
||||
log_step "[9/9] Acceso de red"
|
||||
if [ "$LAPTOP" = "yes" ]; then
|
||||
log_info "Modo portatil: el panel usara el puerto 8080, no hace falta nada mas."
|
||||
else
|
||||
warn "no se pudo habilitar el puerto 80; cambia 'server.port' a 8080 en config.json"
|
||||
PYBIN="$(readlink -f "$DIR/.venv/bin/python3")"
|
||||
if sudo setcap 'cap_net_bind_service=+ep' "$PYBIN" 2>/dev/null; then
|
||||
log_ok "Puerto 80 habilitado"
|
||||
else
|
||||
warn "no se pudo habilitar el puerto 80; cambia 'server.port' a 8080 en config.json"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -271,6 +288,22 @@ else
|
|||
log_warn "FOSFENO instalado con $FOSFENO_WARNINGS aviso(s) (revisa arriba)."
|
||||
fi
|
||||
printf '%s\n' "===================================================$C_RST"
|
||||
if [ "$LAPTOP" = "yes" ]; then
|
||||
cat <<EOF
|
||||
|
||||
FOSFENO instalado en modo portatil.
|
||||
|
||||
Para arrancarlo, desde esta carpeta:
|
||||
./fosfeno
|
||||
|
||||
Se abrira el panel de control en el navegador y una ventana aparte con
|
||||
las visuales (arrastrala al proyector y pulsa F11 para pantalla completa).
|
||||
Para cerrarlo todo, pulsa Ctrl+C en la terminal.
|
||||
|
||||
Para comprobar el sistema sin reinstalar:
|
||||
bash install.sh --check
|
||||
EOF
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
Siguientes pasos:
|
||||
|
|
@ -288,3 +321,4 @@ cat <<EOF
|
|||
Para volver a comprobar el sistema sin reinstalar:
|
||||
bash install.sh --check
|
||||
EOF
|
||||
fi
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue