Commit inicial: G Radio Player
Sistema de automatización de radio en Rust (GTK4 + GStreamer): reproductor principal con crossfade y ducking, scheduler de comerciales, refill de playlist, y herramientas auxiliares (pautaje, parrilla, botonera, visor, buscador, playlist, grabador, reportes). Incluye sistema de skins y modos de Players (paneles de reproducción configurables).
This commit is contained in:
Executable
+405
@@ -0,0 +1,405 @@
|
||||
#!/bin/bash
|
||||
# package-deb.sh — Empaqueta G Radio Player como .deb instalable
|
||||
# Uso: ./package-deb.sh <versión> [--target-dir <dir>] [--suffix <sufijo>]
|
||||
# --target-dir directorio de binarios (default: target/release)
|
||||
# --suffix sufijo al nombre del paquete (ej: _bookworm)
|
||||
set -e
|
||||
|
||||
VERSION="${1:-0.2.8}"
|
||||
TARGET_DIR="target/release"
|
||||
SUFFIX=""
|
||||
|
||||
shift || true
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--target-dir) TARGET_DIR="$2"; shift 2 ;;
|
||||
--suffix) SUFFIX="$2"; shift 2 ;;
|
||||
*) shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
ARCH="$(dpkg --print-architecture)"
|
||||
PKG_NAME="gradio-player"
|
||||
PKG_DIR="${PKG_NAME}_${VERSION}_${ARCH}${SUFFIX}"
|
||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# ── Verificar que los binarios existen ────────────────────────────────────────
|
||||
for BIN in radio-player comercial-scheduler playlist-refill \
|
||||
gr-buscador gr-playlist gr-pautaje gr-parrilla \
|
||||
gr-botonera gr-visor gr-reportes gr-record; do
|
||||
if [ ! -f "$ROOT/$TARGET_DIR/$BIN" ]; then
|
||||
echo "[!] Binario faltante: $TARGET_DIR/$BIN"
|
||||
echo " Ejecuta primero: cargo build --release"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "========================================"
|
||||
echo " Empaquetando $PKG_NAME $VERSION ($ARCH)"
|
||||
echo "========================================"
|
||||
|
||||
# ── Limpiar directorio anterior ───────────────────────────────────────────────
|
||||
rm -rf "$PKG_DIR"
|
||||
|
||||
# ── Verificar que existe la carpeta Time ──────────────────────────────────────
|
||||
if [ -d "$ROOT/assets/Time" ]; then
|
||||
TIME_SRC="$ROOT/assets/Time"
|
||||
elif [ -d "$ROOT/target/data/panel/Time" ]; then
|
||||
TIME_SRC="$ROOT/target/data/panel/Time"
|
||||
else
|
||||
echo "[!] Carpeta Time no encontrada (assets/Time ni target/data/panel/Time)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Estructura de directorios ─────────────────────────────────────────────────
|
||||
mkdir -p "$PKG_DIR/DEBIAN"
|
||||
mkdir -p "$PKG_DIR/usr/local/bin"
|
||||
mkdir -p "$PKG_DIR/usr/local/share/radio-player/Time"
|
||||
mkdir -p "$PKG_DIR/usr/local/share/radio-player/opencode/agents"
|
||||
mkdir -p "$PKG_DIR/usr/local/share/radio-player/opencode/context"
|
||||
mkdir -p "$PKG_DIR/usr/local/share/radio-player/skins"
|
||||
mkdir -p "$PKG_DIR/usr/share/applications"
|
||||
mkdir -p "$PKG_DIR/usr/share/icons/hicolor/48x48/apps"
|
||||
|
||||
# ── Copiar archivos de hora (Time) ───────────────────────────────────────────
|
||||
echo "[*] Copiando carpeta Time..."
|
||||
cp "$TIME_SRC/"* "$PKG_DIR/usr/local/share/radio-player/Time/"
|
||||
|
||||
# ── Copiar contexto de IA (opencode) ─────────────────────────────────────────
|
||||
if [ -d "$ROOT/assets/opencode" ]; then
|
||||
echo "[*] Copiando contexto IA (opencode)..."
|
||||
cp "$ROOT/assets/opencode/AGENTS.md" "$PKG_DIR/usr/local/share/radio-player/opencode/"
|
||||
cp "$ROOT/assets/opencode/opencode.jsonc" "$PKG_DIR/usr/local/share/radio-player/opencode/" 2>/dev/null || true
|
||||
cp "$ROOT/assets/opencode/agents/"* "$PKG_DIR/usr/local/share/radio-player/opencode/agents/"
|
||||
cp "$ROOT/assets/opencode/context/"* "$PKG_DIR/usr/local/share/radio-player/opencode/context/"
|
||||
fi
|
||||
|
||||
# ── Copiar skins de ejemplo ───────────────────────────────────────────────────
|
||||
if [ -d "$ROOT/assets/skins" ]; then
|
||||
echo "[*] Copiando skins de ejemplo..."
|
||||
cp -r "$ROOT/assets/skins/"* "$PKG_DIR/usr/local/share/radio-player/skins/" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Copiar binarios ───────────────────────────────────────────────────────────
|
||||
echo "[*] Copiando binarios..."
|
||||
for BIN in radio-player comercial-scheduler playlist-refill \
|
||||
gr-buscador gr-playlist gr-pautaje gr-parrilla \
|
||||
gr-botonera gr-visor gr-reportes gr-record; do
|
||||
cp "$ROOT/$TARGET_DIR/$BIN" "$PKG_DIR/usr/local/bin/$BIN"
|
||||
chmod 755 "$PKG_DIR/usr/local/bin/$BIN"
|
||||
done
|
||||
|
||||
# ── Lanzador principal ────────────────────────────────────────────────────────
|
||||
echo "[*] Creando lanzador gradio.sh..."
|
||||
cat > "$PKG_DIR/usr/local/bin/gradio.sh" << 'LAUNCHER'
|
||||
#!/bin/bash
|
||||
# Lanzador de G Radio Player — equivalente al run.sh del proyecto fuente
|
||||
|
||||
BIN="/usr/local/bin"
|
||||
HOME_GRADIO="$HOME/.gradio/data"
|
||||
PIDDIR="$HOME_GRADIO/tmp/pids"
|
||||
|
||||
mkdir -p "$PIDDIR"
|
||||
|
||||
# URL del relay internet (usada por relay.rs si "relay habilitado" está activo
|
||||
# en Configuración). Sin esto, relay.rs cae al placeholder wss://relay.example.com/ws
|
||||
# y jamás llega a registrarse — la conexión remota vía Internet queda rota en silencio.
|
||||
export GRADIO_RELAY_URL="${GRADIO_RELAY_URL:-wss://relay.gradio.net/ws}"
|
||||
|
||||
# ── Matar proceso por PID guardado + búsqueda por nombre ─────────────────────
|
||||
kill_aux() {
|
||||
local name="$1"
|
||||
local pidfile="$PIDDIR/$name.pid"
|
||||
|
||||
if [ -f "$pidfile" ]; then
|
||||
local pid
|
||||
pid=$(cat "$pidfile" 2>/dev/null)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
echo " Deteniendo $name (PID $pid)..."
|
||||
kill "$pid" 2>/dev/null
|
||||
for i in $(seq 1 6); do
|
||||
sleep 0.5
|
||||
kill -0 "$pid" 2>/dev/null || break
|
||||
done
|
||||
kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null
|
||||
fi
|
||||
rm -f "$pidfile"
|
||||
fi
|
||||
|
||||
pkill -x "$name" 2>/dev/null
|
||||
sleep 0.3
|
||||
}
|
||||
|
||||
# ── Matar instancias previas ──────────────────────────────────────────────────
|
||||
echo "==> Deteniendo instancias previas (si las hay)..."
|
||||
kill_aux "comercial-scheduler"
|
||||
kill_aux "playlist-refill"
|
||||
sleep 0.5
|
||||
|
||||
# ── Crear estructura de directorios ──────────────────────────────────────────
|
||||
mkdir -p "$HOME_GRADIO/tmp"
|
||||
mkdir -p "$HOME_GRADIO/comerciales"
|
||||
mkdir -p "$HOME_GRADIO/eventos-espera"
|
||||
mkdir -p "$HOME_GRADIO/eventos"
|
||||
mkdir -p "$HOME_GRADIO/parrilla"
|
||||
mkdir -p "$HOME_GRADIO/reporte"
|
||||
mkdir -p "$HOME_GRADIO/panel"
|
||||
mkdir -p "$HOME/G Radio/inicio-espacio-pub"
|
||||
mkdir -p "$HOME/G Radio/fin-espacio-pub"
|
||||
mkdir -p "$HOME/G Radio/comerciales"
|
||||
|
||||
# ── Instalar carpeta Time (audios de hora) si aún no existe ──────────────────
|
||||
if [ ! -d "$HOME_GRADIO/panel/Time" ]; then
|
||||
echo "==> Instalando carpeta Time en $HOME_GRADIO/panel/..."
|
||||
cp -r /usr/local/share/radio-player/Time "$HOME_GRADIO/panel/Time"
|
||||
fi
|
||||
|
||||
# ── Instalar contexto IA (opencode) si no existe o está desactualizado ───────
|
||||
OPENCODE_SRC="/usr/local/share/radio-player/opencode"
|
||||
OPENCODE_DST="$HOME_GRADIO/opencode"
|
||||
if [ -d "$OPENCODE_SRC" ] && [ ! -f "$OPENCODE_DST/AGENTS.md" ]; then
|
||||
echo "==> Instalando contexto IA en $OPENCODE_DST/..."
|
||||
mkdir -p "$OPENCODE_DST/agents" "$OPENCODE_DST/context"
|
||||
cp -r "$OPENCODE_SRC/"* "$OPENCODE_DST/"
|
||||
fi
|
||||
|
||||
# ── Instalar skins de ejemplo (solo los que aún no existan) ──────────────────
|
||||
SKINS_SRC="/usr/local/share/radio-player/skins"
|
||||
SKINS_DST="$HOME_GRADIO/skins"
|
||||
if [ -d "$SKINS_SRC" ]; then
|
||||
mkdir -p "$SKINS_DST"
|
||||
for skin_dir in "$SKINS_SRC"/*/; do
|
||||
[ -d "$skin_dir" ] || continue
|
||||
skin_name=$(basename "$skin_dir")
|
||||
if [ ! -d "$SKINS_DST/$skin_name" ]; then
|
||||
echo "==> Instalando skin '$skin_name' en $SKINS_DST/..."
|
||||
cp -r "$skin_dir" "$SKINS_DST/$skin_name"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# ── Migración device → gradio.config (compatibilidad con versiones anteriores)
|
||||
DEVICE_FILE="$HOME_GRADIO/tmp/device"
|
||||
CONFIG_FILE="$HOME_GRADIO/tmp/gradio.config"
|
||||
if [ -f "$DEVICE_FILE" ] && [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "==> Migrando device → gradio.config..."
|
||||
MIX=$(cat "$HOME_GRADIO/mix" 2>/dev/null || echo "3.0")
|
||||
paste -d"\n" "$DEVICE_FILE" /dev/null > "$CONFIG_FILE"
|
||||
printf "G Radio\n%s\n" "$MIX" >> "$CONFIG_FILE"
|
||||
rm -f "$DEVICE_FILE"
|
||||
fi
|
||||
|
||||
# ── Archivos de configuración por defecto ─────────────────────────────────────
|
||||
[ -f "$HOME_GRADIO/tmp/upvol" ] || echo "90" > "$HOME_GRADIO/tmp/upvol"
|
||||
[ -f "$HOME_GRADIO/tmp/downvol" ] || echo "20" > "$HOME_GRADIO/tmp/downvol"
|
||||
[ -f "$HOME_GRADIO/mix" ] || echo "3" > "$HOME_GRADIO/mix"
|
||||
|
||||
# ── Limpiar listas temporales (toma la programación de la hora actual) ────────
|
||||
> "$HOME_GRADIO/tmp/comercialeslist4"
|
||||
> "$HOME_GRADIO/tmp/eventos-esperalist"
|
||||
> "$HOME_GRADIO/tmp/eventoslist"
|
||||
> "$HOME_GRADIO/tmp/playlist4"
|
||||
echo "==> Listas temporales limpiadas."
|
||||
|
||||
# ── Iniciar daemons auxiliares ────────────────────────────────────────────────
|
||||
echo "==> Iniciando comercial-scheduler..."
|
||||
"$BIN/comercial-scheduler" &
|
||||
SCHED_PID=$!
|
||||
echo "$SCHED_PID" > "$PIDDIR/comercial-scheduler.pid"
|
||||
echo " PID: $SCHED_PID"
|
||||
|
||||
echo "==> Iniciando playlist-refill..."
|
||||
"$BIN/playlist-refill" &
|
||||
REFILL_PID=$!
|
||||
echo "$REFILL_PID" > "$PIDDIR/playlist-refill.pid"
|
||||
echo " PID: $REFILL_PID"
|
||||
|
||||
# ── Watchdog: verifica cada 30s que los daemons siguen vivos ──────────────────
|
||||
watchdog() {
|
||||
while true; do
|
||||
sleep 30
|
||||
kill -0 "$RADIO_PID" 2>/dev/null || break
|
||||
|
||||
if ! kill -0 "$SCHED_PID" 2>/dev/null; then
|
||||
echo "==> WATCHDOG: comercial-scheduler caído, reiniciando..."
|
||||
"$BIN/comercial-scheduler" &
|
||||
SCHED_PID=$!
|
||||
echo "$SCHED_PID" > "$PIDDIR/comercial-scheduler.pid"
|
||||
fi
|
||||
|
||||
if ! kill -0 "$REFILL_PID" 2>/dev/null; then
|
||||
echo "==> WATCHDOG: playlist-refill caído, reiniciando..."
|
||||
"$BIN/playlist-refill" &
|
||||
REFILL_PID=$!
|
||||
echo "$REFILL_PID" > "$PIDDIR/playlist-refill.pid"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# ── Inhibir suspensión / DPMS (ARM: previene congelamiento del main loop GTK4) ──
|
||||
if command -v systemd-inhibit &>/dev/null; then
|
||||
echo "==> Inhibiendo idle con systemd-inhibit..."
|
||||
RUST_LOG=info systemd-inhibit \
|
||||
--what=idle \
|
||||
--who="G Radio Player" \
|
||||
--why="Reproducción de audio en curso" \
|
||||
--mode=block \
|
||||
"$BIN/radio-player" "$@" &
|
||||
RADIO_PID=$!
|
||||
else
|
||||
xset s off 2>/dev/null || true
|
||||
xset -dpms 2>/dev/null || true
|
||||
xset s noblank 2>/dev/null || true
|
||||
echo "==> Iniciando radio-player..."
|
||||
RUST_LOG=info "$BIN/radio-player" "$@" &
|
||||
RADIO_PID=$!
|
||||
fi
|
||||
|
||||
watchdog &
|
||||
WATCHDOG_PID=$!
|
||||
|
||||
wait "$RADIO_PID"
|
||||
|
||||
# ── Limpieza al salir ─────────────────────────────────────────────────────────
|
||||
echo "==> Cerrando procesos auxiliares..."
|
||||
kill "$WATCHDOG_PID" 2>/dev/null
|
||||
kill_aux "comercial-scheduler"
|
||||
kill_aux "playlist-refill"
|
||||
rm -f "$PIDDIR/comercial-scheduler.pid" "$PIDDIR/playlist-refill.pid"
|
||||
echo "==> Terminado."
|
||||
LAUNCHER
|
||||
chmod 755 "$PKG_DIR/usr/local/bin/gradio.sh"
|
||||
|
||||
# ── Icono ─────────────────────────────────────────────────────────────────────
|
||||
if [ -f "$ROOT/assets/gradio.png" ]; then
|
||||
cp "$ROOT/assets/gradio.png" "$PKG_DIR/usr/share/icons/hicolor/48x48/apps/gradio-player.png"
|
||||
chmod 644 "$PKG_DIR/usr/share/icons/hicolor/48x48/apps/gradio-player.png"
|
||||
fi
|
||||
|
||||
# ── Entrada de escritorio ─────────────────────────────────────────────────────
|
||||
cat > "$PKG_DIR/usr/share/applications/com.gradio.radio-player.desktop" << DESKTOP
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=G Radio Player
|
||||
GenericName=Radio Automation
|
||||
Comment=Sistema de automatización de radio profesional
|
||||
Exec=/usr/local/bin/gradio.sh
|
||||
Icon=gradio-player
|
||||
Categories=AudioVideo;Audio;Player;
|
||||
Terminal=false
|
||||
StartupNotify=true
|
||||
Keywords=radio;audio;player;automation;
|
||||
DESKTOP
|
||||
|
||||
# ── DEBIAN/control ────────────────────────────────────────────────────────────
|
||||
echo "[*] Generando DEBIAN/control..."
|
||||
INSTALLED_SIZE=$(du -sk "$PKG_DIR/usr" | cut -f1)
|
||||
|
||||
cat > "$PKG_DIR/DEBIAN/control" << CONTROL
|
||||
Package: gradio-player
|
||||
Version: ${VERSION}
|
||||
Architecture: ${ARCH}
|
||||
Maintainer: G Radio <gradio@example.com>
|
||||
Installed-Size: ${INSTALLED_SIZE}
|
||||
Depends: libgtk-4-1 (>= 4.6),
|
||||
libgstreamer1.0-0 (>= 1.20),
|
||||
libgstreamer-plugins-base1.0-0 (>= 1.20),
|
||||
gstreamer1.0-plugins-base (>= 1.20),
|
||||
gstreamer1.0-plugins-good (>= 1.20),
|
||||
gstreamer1.0-plugins-bad (>= 1.20),
|
||||
gstreamer1.0-plugins-ugly (>= 1.20),
|
||||
gstreamer1.0-libav (>= 1.20),
|
||||
gstreamer1.0-alsa | gstreamer1.0-pulseaudio,
|
||||
ffmpeg,
|
||||
libc6 (>= 2.17)
|
||||
Section: sound
|
||||
Priority: optional
|
||||
Description: G Radio Player — sistema de automatización de radio
|
||||
Reproductor profesional para emisoras de radio con programación automática
|
||||
de música, comerciales y eventos. Incluye interfaz GTK4, crossfading,
|
||||
duck de volumen y gestión de parrilla horaria.
|
||||
.
|
||||
Componentes: radio-player, comercial-scheduler, playlist-refill,
|
||||
gr-pautaje, gr-parrilla, gr-botonera, gr-visor, gr-buscador, gr-playlist,
|
||||
gr-record.
|
||||
CONTROL
|
||||
|
||||
# ── DEBIAN/postinst ───────────────────────────────────────────────────────────
|
||||
cat > "$PKG_DIR/DEBIAN/postinst" << 'POSTINST'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Limpiar entrada de escritorio de versiones antiguas (renombrada a
|
||||
# com.gradio.radio-player.desktop para que el app_id coincida con el nombre
|
||||
# del .desktop — requerido para que Wayland resuelva el ícono correctamente).
|
||||
rm -f /usr/share/applications/gradio-player.desktop
|
||||
|
||||
# Actualizar caché de iconos y menú de escritorio
|
||||
if command -v gtk-update-icon-cache &>/dev/null; then
|
||||
gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true
|
||||
fi
|
||||
if command -v update-desktop-database &>/dev/null; then
|
||||
update-desktop-database /usr/share/applications 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "G Radio Player instalado correctamente."
|
||||
echo "Ejecutar: gradio.sh o buscar 'G Radio Player' en el menú."
|
||||
POSTINST
|
||||
chmod 755 "$PKG_DIR/DEBIAN/postinst"
|
||||
|
||||
# ── DEBIAN/prerm ──────────────────────────────────────────────────────────────
|
||||
# No matamos procesos aquí: Linux mantiene el ejecutable anterior en memoria
|
||||
# hasta que cierre (safe inode replacement). Tener pkill en prerm rompe dpkg
|
||||
# al actualizar porque el prerm de la versión INSTALADA corre primero — y si
|
||||
# esa versión tenía pkill -f (bug histórico), mata al propio dpkg.
|
||||
cat > "$PKG_DIR/DEBIAN/prerm" << 'PRERM'
|
||||
#!/bin/bash
|
||||
exit 0
|
||||
PRERM
|
||||
chmod 755 "$PKG_DIR/DEBIAN/prerm"
|
||||
|
||||
# ── DEBIAN/postrm ─────────────────────────────────────────────────────────────
|
||||
cat > "$PKG_DIR/DEBIAN/postrm" << 'POSTRM'
|
||||
#!/bin/bash
|
||||
# Solo borrar archivos en remove/purge — nunca en upgrade/failed-upgrade.
|
||||
# Durante un upgrade dpkg instala el nuevo paquete ANTES de correr este
|
||||
# postrm; si borramos incondicionalmente, eliminamos los binarios recién
|
||||
# instalados por la versión nueva.
|
||||
case "$1" in
|
||||
remove|purge)
|
||||
for BIN in radio-player comercial-scheduler playlist-refill \
|
||||
gradio.sh gr-buscador gr-playlist gr-pautaje gr-parrilla \
|
||||
gr-botonera gr-visor gr-reportes gr-record; do
|
||||
rm -f "/usr/local/bin/$BIN"
|
||||
done
|
||||
rm -rf /usr/local/share/radio-player
|
||||
rm -f /usr/share/applications/com.gradio.radio-player.desktop
|
||||
rm -f /usr/share/applications/gradio-player.desktop # limpieza de versiones antiguas
|
||||
rm -f /usr/share/icons/hicolor/48x48/apps/gradio-player.png
|
||||
command -v gtk-update-icon-cache &>/dev/null && \
|
||||
gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true
|
||||
command -v update-desktop-database &>/dev/null && \
|
||||
update-desktop-database /usr/share/applications 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
POSTRM
|
||||
chmod 755 "$PKG_DIR/DEBIAN/postrm"
|
||||
|
||||
# ── Construir el .deb ─────────────────────────────────────────────────────────
|
||||
echo "[*] Construyendo paquete .deb..."
|
||||
dpkg-deb --build --root-owner-group "$PKG_DIR"
|
||||
|
||||
DEB_FILE="${PKG_DIR}.deb"
|
||||
SIZE=$(du -sh "$DEB_FILE" | cut -f1)
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Paquete listo: $DEB_FILE ($SIZE)"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo " Instalar: sudo dpkg -i $DEB_FILE"
|
||||
echo " O con apt: sudo apt install ./$DEB_FILE"
|
||||
echo ""
|
||||
echo " Desinstalar: sudo apt remove gradio-player"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user