Primera version. Cinco motores (projectM, Butterchurn, Hydra, Shaders GLSL y mezclador VJ con camara y video), panel de control web, deteccion de BPM propia, pantalla de conexion con codigo QR, instalador robusto para Raspberry Pi 4 y 5 y documentacion completa en docs/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
290 lines
12 KiB
Bash
Executable file
290 lines
12 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# ===========================================================================
|
|
# FOSFENO :: instalador para Raspberry Pi OS Bookworm (Raspberry Pi 4 y 5)
|
|
#
|
|
# Uso: bash install.sh # instala todo (incluido projectM)
|
|
# bash install.sh --no-projectm # omite la compilacion de projectM
|
|
# bash install.sh --check # solo comprueba el sistema, no instala
|
|
# ===========================================================================
|
|
set -uo pipefail
|
|
|
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
source "$DIR/scripts/lib.sh"
|
|
|
|
MODE="install"
|
|
SKIP_PM="no"
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--no-projectm) SKIP_PM="yes" ;;
|
|
--check) MODE="check" ;;
|
|
*) echo "Opcion desconocida: $arg"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
# Versiones minimas requeridas
|
|
MIN_PYTHON="3.9"
|
|
MIN_NODE="16"
|
|
MIN_NPM="8"
|
|
MIN_CMAKE="3.21"
|
|
|
|
printf '%s\n' "$C_BLD==================================================="
|
|
printf '%s\n' " FOSFENO :: instalador ($DIR)"
|
|
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
|
|
|
|
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
|
|
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
|
|
# ---------------------------------------------------------------------------
|
|
if [ "$MODE" = "check" ]; then
|
|
log_step "Comprobando herramientas ya instaladas"
|
|
require_version "Python" "python3 --version" "$MIN_PYTHON" || true
|
|
require_version "Node.js" "node --version" "$MIN_NODE" || true
|
|
require_version "npm" "npm --version" "$MIN_NPM" || true
|
|
require_version "CMake" "cmake --version" "$MIN_CMAKE" || true
|
|
if need_cmd chromium-browser || need_cmd chromium; then
|
|
log_ok "Chromium presente"
|
|
else
|
|
log_fail "Chromium no encontrado"
|
|
fi
|
|
need_cmd git && log_ok "git presente" || log_fail "git no encontrado"
|
|
need_cmd projectMSDL && log_ok "projectM (projectMSDL) presente" \
|
|
|| log_warn "projectM no instalado (opcional)"
|
|
printf '\n'
|
|
[ "$FOSFENO_WARNINGS" -eq 0 ] && log_ok "Comprobacion terminada sin avisos" \
|
|
|| log_warn "Comprobacion terminada con $FOSFENO_WARNINGS aviso(s)"
|
|
exit 0
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Paquetes del sistema
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[2/9] Instalando dependencias del sistema (apt)"
|
|
sudo apt-get update
|
|
if sudo apt-get install -y \
|
|
python3 python3-venv python3-pip \
|
|
chromium-browser \
|
|
nodejs npm \
|
|
git cmake build-essential pkg-config \
|
|
libsdl2-dev libgles2-mesa-dev mesa-common-dev libglm-dev libpoco-dev \
|
|
pulseaudio-utils \
|
|
v4l-utils \
|
|
avahi-daemon \
|
|
xdotool unclutter; then
|
|
log_ok "Paquetes apt instalados"
|
|
else
|
|
log_fail "Fallo al instalar paquetes apt"
|
|
exit 1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Verificacion de versiones de las herramientas
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[3/9] Verificando versiones de las herramientas"
|
|
require_version "Python" "python3 --version" "$MIN_PYTHON" \
|
|
|| { log_fail "Python demasiado antiguo; aborto"; exit 1; }
|
|
require_version "Node.js" "node --version" "$MIN_NODE" \
|
|
|| warn "Node.js antiguo: 'npm install' podria fallar"
|
|
require_version "npm" "npm --version" "$MIN_NPM" || true
|
|
if [ "$SKIP_PM" = "no" ]; then
|
|
require_version "CMake" "cmake --version" "$MIN_CMAKE" \
|
|
|| { warn "CMake antiguo: projectM no se compilara"; SKIP_PM="yes"; }
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Entorno Python
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[4/9] Creando el entorno virtual de Python"
|
|
python3 -m venv "$DIR/.venv"
|
|
"$DIR/.venv/bin/pip" install --quiet --upgrade pip
|
|
"$DIR/.venv/bin/pip" install --quiet -r "$DIR/backend/requirements.txt"
|
|
if "$DIR/.venv/bin/python3" -c "import flask, flask_socketio" 2>/dev/null; then
|
|
log_ok "Entorno Python listo (flask, flask-socketio)"
|
|
else
|
|
log_fail "Las dependencias de Python no se importan correctamente"
|
|
exit 1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Librerias web (Butterchurn, Hydra, Socket.IO, CodeMirror)
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[5/9] Descargando librerias de visuales (npm)"
|
|
cd "$DIR/web"
|
|
if npm install --no-audit --no-fund --loglevel=error; then
|
|
log_ok "Paquetes npm descargados"
|
|
else
|
|
log_fail "Fallo en 'npm install'"
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$DIR/web/lib/codemirror"
|
|
# Copia un fichero y comprueba que existe y no esta vacio
|
|
copy_lib() { # copy_lib <origen> <destino> <descripcion>
|
|
if cp "$1" "$2" 2>/dev/null && [ -s "$2" ]; then
|
|
log_ok "$3"
|
|
else
|
|
warn "no se pudo copiar: $3 ($1)"
|
|
fi
|
|
}
|
|
copy_lib node_modules/butterchurn/dist/butterchurn.min.js \
|
|
lib/butterchurn.min.js "Butterchurn"
|
|
copy_lib node_modules/butterchurn-presets/dist/base.min.js \
|
|
lib/butterchurn-presets.min.js "Presets de Butterchurn"
|
|
copy_lib node_modules/socket.io-client/dist/socket.io.min.js \
|
|
lib/socket.io.min.js "Socket.IO"
|
|
copy_lib node_modules/qrcode-generator/qrcode.js \
|
|
lib/qrcode.js "Generador de codigo QR"
|
|
copy_lib node_modules/codemirror/lib/codemirror.js \
|
|
lib/codemirror/codemirror.js "CodeMirror (editor)"
|
|
copy_lib node_modules/codemirror/lib/codemirror.css \
|
|
lib/codemirror/codemirror.css "CodeMirror (estilos)"
|
|
copy_lib node_modules/codemirror/mode/javascript/javascript.js \
|
|
lib/codemirror/javascript.js "CodeMirror (modo JavaScript)"
|
|
copy_lib node_modules/codemirror/mode/clike/clike.js \
|
|
lib/codemirror/clike.js "CodeMirror (modo GLSL)"
|
|
copy_lib node_modules/codemirror/theme/material-darker.css \
|
|
lib/codemirror/material-darker.css "CodeMirror (tema)"
|
|
# Hydra no siempre ubica el build en el mismo sitio: probamos varias rutas
|
|
if cp node_modules/hydra-synth/dist/hydra-synth.js lib/hydra-synth.js 2>/dev/null && [ -s lib/hydra-synth.js ]; then
|
|
log_ok "Hydra"
|
|
elif cp node_modules/hydra-synth/build/hydra-synth.js lib/hydra-synth.js 2>/dev/null && [ -s lib/hydra-synth.js ]; then
|
|
log_ok "Hydra (build/)"
|
|
else
|
|
warn "no se encontro el build de hydra-synth en node_modules; revisa la ruta"
|
|
fi
|
|
cd "$DIR"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 6. projectM nativo (compilado desde fuente)
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[6/9] projectM (visualizador nativo)"
|
|
if [ "$SKIP_PM" = "yes" ]; then
|
|
log_info "projectM omitido"
|
|
elif command -v projectMSDL >/dev/null 2>&1; then
|
|
log_ok "projectM ya estaba instalado ($(command -v projectMSDL))"
|
|
else
|
|
log_info "Compilando projectM desde fuente (puede tardar 10-20 min en una Pi)..."
|
|
if bash "$DIR/scripts/build-projectm.sh"; then
|
|
command -v projectMSDL >/dev/null 2>&1 \
|
|
&& log_ok "projectM compilado e instalado" \
|
|
|| warn "projectM compilo pero 'projectMSDL' no esta en el PATH"
|
|
else
|
|
warn "projectM no se pudo compilar; FOSFENO seguira con Butterchurn, Hydra y Shaders"
|
|
fi
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 7. Presets de projectM y carpeta de videos
|
|
# ---------------------------------------------------------------------------
|
|
log_step "[7/9] Recursos (presets de projectM, carpeta de videos)"
|
|
mkdir -p "$DIR/data/presets-projectm" "$DIR/data/videos"
|
|
if [ -z "$(ls -A "$DIR/data/presets-projectm" 2>/dev/null)" ]; then
|
|
if git clone --depth 1 \
|
|
https://github.com/projectM-visualizer/presets-cream-of-the-crop.git \
|
|
"$DIR/data/presets-projectm" 2>/dev/null; then
|
|
N=$(find "$DIR/data/presets-projectm" -name '*.milk' | wc -l)
|
|
log_ok "Presets de projectM descargados ($N presets)"
|
|
else
|
|
warn "no se pudieron descargar los presets de projectM"
|
|
fi
|
|
else
|
|
log_ok "Presets de projectM ya presentes"
|
|
fi
|
|
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
|
|
|
|
# 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
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 9. Permiso para el puerto 80
|
|
# ---------------------------------------------------------------------------
|
|
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"
|
|
else
|
|
warn "no se pudo habilitar el puerto 80; cambia 'server.port' a 8080 en config.json"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Resumen final
|
|
# ---------------------------------------------------------------------------
|
|
printf '\n%s\n' "$C_BLD==================================================="
|
|
if [ "$FOSFENO_WARNINGS" -eq 0 ]; then
|
|
log_ok "FOSFENO instalado correctamente, sin avisos."
|
|
else
|
|
log_warn "FOSFENO instalado con $FOSFENO_WARNINGS aviso(s) (revisa arriba)."
|
|
fi
|
|
printf '%s\n' "===================================================$C_RST"
|
|
cat <<EOF
|
|
|
|
Siguientes pasos:
|
|
1. Activa el login automatico al escritorio:
|
|
sudo raspi-config -> System Options -> Boot / Auto Login
|
|
-> Desktop Autologin
|
|
2. Reinicia: sudo reboot
|
|
|
|
Como entrar en el panel de control:
|
|
- Al arrancar, el proyector muestra un codigo QR y la direccion.
|
|
Escanea el QR con el movil y se abre el panel. Mas facil imposible.
|
|
- Si prefieres escribirla: http://$HOSTNAME_WANT.local/
|
|
- El movil debe estar en la misma red (WiFi o cable) que la Raspberry.
|
|
|
|
Para volver a comprobar el sistema sin reinstalar:
|
|
bash install.sh --check
|
|
EOF
|