Con TODOS los códigos enteros listos para copiar/pegar. No tendrás que “reemplazar trozos”; simplemente pega cada bloque donde se indica.
A) Raspberry Pi — Dependencias y preparación
# A.1 Actualiza con full-upgrade (tu receta “que funcionó”) sudo apt update sudo apt full-upgrade -y # A.2 Instala paquetes exactos que usas sudo apt install -y mpv socat netcat-openbsd dos2unix # A.3 Prepara logs y permisos sudo touch /home/arcade/mostrar_rom_debug.log sudo chown -R $USER:$USER /home/arcade # (si $USER no es 'arcade', usa:) sudo chown -R arcade:arcade /home/arcade # A.4 (Recomendado) añade al usuario 'arcade' a grupos de vídeo/audio para KMS/DRM sudo usermod -aG video,render,audio arcade # A.5 Comprobaciones rápidas which mpv && mpv --version | head -n 1 which nc && nc -h 2>&1 | head -n 1 which socat && socat -V | head -n 1
B) Raspberry Pi — Arranque completamente en negro
# B.1 Silencia arco iris y avisos del firmware
sudo awk '
/^\[all\]/ {inall=1}
inall && $0 ~ /^disable_splash=/ { $0="disable_splash=1"; seen1=1 }
inall && $0 ~ /^avoid_warnings=/ { $0="avoid_warnings=1"; seen2=1 }
{ print }
END { if (!seen1) print "disable_splash=1"; if (!seen2) print "avoid_warnings=1";
}
' /boot/firmware/config.txt | sudo tee /boot/firmware/config.txt >/dev/null
# B.2 Quita mensajes del kernel y el cursor (cmdline.txt = UNA sola línea)
FILE=/boot/firmware/cmdline.txt
LINE=$(cat "$FILE")
add_arg(){ ARG="$1"; echo "$LINE" | grep -qw "$ARG" || LINE="$LINE $ARG"; }
add_arg console=tty3
add_arg quiet
add_arg splash
add_arg loglevel=0
add_arg vt.global_cursor_default=0
printf '%s\n' "$LINE" | sudo tee "$FILE" >/dev/null
# B.3 Evita “flash” del login en TTY1
sudo systemctl mask getty@tty1.service
# B.4 (Opcional) Plymouth “casi vacío”
sudo apt install -y plymouth
sudo plymouth-set-default-theme text
# B.5 Verificaciones
grep -Eo 'console=tty3|quiet|splash|loglevel=0|vt\.global_cursor_default=0' /boot/firmware/cmdline.txt
grep -E 'disable_splash=|avoid_warnings=' /boot/firmware/config.txt
systemctl is-enabled getty@tty1.service
C) Raspberry Pi — Estructura de carpetas
mkdir -p /home/arcade/{default,sistemas,mame,megadrive}
# (opcional) logo de fallback:
# cp /ruta/a/tu/logo.mp4 /home/arcade/default/logo.mp4
ls -ld /home/arcade/{default,sistemas,mame,megadrive}
D) Raspberry Pi — Wrapper IPC (BASH)
Archivo: /usr/local/bin/mostrar_rom_ipc.sh
#!/bin/bash
set -euo pipefail
# ============================
# mostrar_rom_ipc.sh (con alias + separador ":" + normalización ROM)
# ============================
# Entrada:
# - "sistema" (ej: mame)
# - "sistema:rom" (o con '|' '/' '\')
# Búsqueda por ROM:
# 1) /home/arcade/<sistema>/<rom>.(mp4|gif|jpg|png)
# 2) si hay alias en /home/arcade/system_aliases.conf -> /home/arcade/<alias>>
# 3) /home/arcade/sistemas/<sistema>.(mp4|gif|jpg|png)
# 4) fallback logo: /home/arcade/default/logo.* -> /home/arcade/sistemas/lo>
# Prioridad de formatos: mp4 > gif > jpg > png
MSG="${1:-}"
SOCK="/run/mpv-marquee.sock"
LOG="/home/arcade/mostrar_rom_debug.log"
ROOT="/home/arcade"
SYS_DIR="$ROOT/sistemas"
ALIAS_FILE="$ROOT/system_aliases.conf"
# Si quieres búsqueda global opcional por cualquier sistema (último recurso), p>
SEARCH_ANY_SYSTEM=1
# ---------- Utilidades ----------
ts() { date +"%Y-%m-%d %H:%M:%S,%3N"; }
log() { printf "%s %s\n" "$(ts)" "$*" >> "$LOG"; }
ensure_socket() {
for i in $(seq 1 50); do [[ -S "$SOCK" ]] && return 0; sleep 0.2; done
systemctl start marquee-mpv.service >/dev/null 2>&1 || true
for i in $(seq 1 50); do [[ -S "$SOCK" ]] && return 0; sleep 0.2; done
return 1
}
send_ipc_once() { local json="$1"; printf '%s\n' "$json" | socat - "$SOCK" >/de>
send_ipc() { local json="$1"; send_ipc_once "$json" || { ensure_socket && >
# Devuelve primer asset existente según prioridad
pick_asset() {
local base="$1" f
for ext in mp4 gif jpg png; do
f="${base}.${ext}"
[[ -f "$f" ]] && { echo "$f"; return 0; }
done
return 1
}
mpv_load() {
local media="$1" esc
esc=$(printf '%s' "$media" | sed 's/\\/\\\\/g; s/"/\\"/g')
send_ipc '{"command":["set","loop-file","inf"]}' || true
send_ipc "{\"command\":[\"loadfile\",\"$esc\",\"replace\"]}" || true
}
play_fallback_logo() {
local asset=""
if asset=$(pick_asset "$ROOT/default/logo"); then
log "[PLAY] fallback default: $asset"; mpv_load "$asset"; return
fi
if asset=$(pick_asset "$SYS_DIR/logo"); then
log "[PLAY] fallback sistemas: $asset"; mpv_load "$asset"; return
fi
log "[WARN] Sin logo de fallback disponible."
}
# Leer alias: devuelve el sistema canónico para $1 si existe (case-insensitive)
map_alias() {
local sys_in="$1"
local sys_l="${sys_in,,}"
local k v kl vl
[[ -f "$ALIAS_FILE" ]] || return 1
while IFS='=' read -r k v || [[ -n "$k" ]]; do
# --- único cambio: tolerar CRLF en el .conf ---
k="${k//$'\r'/}"; v="${v//$'\r'/}"
[[ -z "${k//[[:space:]]/}" ]] && continue
[[ "$k" =~ ^[[:space:]]*# ]] && continue
k="$(printf '%s' "$k" | awk '{$1=$1;print}')"
v="$(printf '%s' "$v" | awk '{$1=$1;print}')"
kl="${k,,}"; vl="${v,,}"
if [[ "$kl" == "$sys_l" ]]; then printf '%s' "$vl"; return 0; fi
done < "$ALIAS_FILE"
return 1
}
# Búsqueda global opcional por cualquier sistema (excluye 'sistemas' y 'default>
find_any_system_asset() {
local rom="$1" asset=""
if asset=$(pick_asset "$ROOT/mame/$rom"); then echo "$asset"; return 0; fi
local d base
for d in "$ROOT"/*; do
[[ -d "$d" ]] || continue
base="${d##*/}"
[[ "$base" == "sistemas" || "$base" == "default" || "$base" == "mame" ]] &&>
if asset=$(pick_asset "$d/$rom"); then echo "$asset"; return 0; fi
done
return 1
}
# ---------- Entrada / Parse ----------
if [[ -z "${MSG// }" ]]; then IFS= read -r MSG || true; fi
MSG=${MSG//\"/}
MSG="$(printf '%s' "$MSG" | tr -d '\r\n' | awk '{$1=$1;print}')"
[[ -z "$MSG" ]] && { log "[RX] Mensaje vacío, nada que hacer."; exit 0; }
log "[RX] raw=<${MSG}>"
shopt -s nocasematch
if [[ "$MSG" == "logo" || "$MSG" == "default" || "$MSG" == "marquee" ]]; then
play_fallback_logo; exit 0
fi
shopt -u nocasematch
# --- Separador: prioriza ":" (lo que envías desde Windows); si no hay, prueba >
sep=""
if [[ "$MSG" == *:* ]]; then sep=":"
elif [[ "$MSG" == *"|"* ]]; then sep="|"
elif [[ "$MSG" == *"/"* ]]; then sep="/"
elif [[ "$MSG" == *\\* ]]; then sep="\\"
fi
log "[SEP] sep='<${sep}>' msg='<${MSG}>'"
system=""
rom=""
if [[ -z "$sep" ]]; then
system="$MSG"
else
system="${MSG%%"$sep"*}"
rom="${MSG#*"$sep"}"
fi
# Limpieza básica
system="$(printf '%s' "$system" | awk '{$1=$1;print}')"
rom="$(printf '%s' "$rom" | awk '{$1=$1;print}')"
# --- Normalización ROM (mínimos cambios) ---
if [[ -n "$rom" ]]; then
rom_orig="$rom"
rom="${rom//|/,}" # '|' -> ','
rom="${rom//,v /, }" # ',v ' -> ', '
rom="${rom//,v/, }" # ',v' -> ', ' (por si no vino el espacio)
rom="${rom//, /, }" # colapsar doble espacio tras coma
if [[ "$rom" != "$rom_orig" ]]; then
log "[NORM] rom '<$rom_orig>' -> '<$rom>'"
fi
fi
log "[PARSE] system=<${system}> rom=<${rom}>"
# ---------- Resolución ----------
asset=""
if [[ -n "$rom" ]]; then
# 1) /home/arcade/<sistema>/<rom>.*
if asset=$(pick_asset "$ROOT/$system/$rom"); then
log "[PLAY] rom asset: $asset"; mpv_load "$asset"; exit 0
fi
# 2) alias -> sistema canónico (ej.: arcade -> mame)
alias_sys="$(map_alias "$system" || true)"
if [[ -n "${alias_sys:-}" ]]; then
if asset=$(pick_asset "$ROOT/$alias_sys/$rom"); then
log "[PLAY] alias asset: $system -> $alias_sys : $asset"; mpv_load "$asse>
fi
fi
# 3) (opcional) búsqueda global por cualquier sistema
if [[ "$SEARCH_ANY_SYSTEM" -eq 1 ]]; then
if asset=$(find_any_system_asset "$rom"); then
log "[PLAY] any-system asset: $asset"; mpv_load "$asset"; exit 0
fi
fi
# 4) Fallback al arte del sistema</rom></sistema>
if asset=$(pick_asset "$SYS_DIR/$system"); then
log "[PLAY] fallback system asset: $asset"; mpv_load "$asset"; exit 0
fi
# 5) Logo
log "[MISS] Sin arte de ROM (incl. alias) ni de sistema."; play_fallback_logo>
else
# Solo sistema
if asset=$(pick_asset "$SYS_DIR/$system"); then
log "[PLAY] system asset: $asset"; mpv_load "$asset"; exit 0
fi
log "[MISS] Sin arte del sistema."; play_fallback_logo; exit 0
fi
E) Raspberry Pi — Alias de sistemas
Archivo: /home/arcade/system_aliases.conf
# alias_de_sistema = sistema_canonico mame = mame arcade = mame vertical = mame favorites = mame recent = mame megadrive = megadrive # all → (mejor sin alias, ya buscamos global) # Normaliza finales de línea si editaste en Windows sudo dos2unix /home/arcade/system_aliases.conf 2>/dev/null || sudo sed -i 's/\r$//' /home/arcade/system_aliases.conf
(Puedes añadir más alias/sistemas cuando quieras.)
F) Raspberry Pi — Servicio MPV (DRM/KMS, el tuyo “tal cual”)
Archivo: /etc/systemd/system/marquee-mpv.service
sudo tee /etc/systemd/system/marquee-mpv.service >/dev/null <<'EOF' [Unit] Description=Persistent mpv for marquee display (DRM/KMS + IPC) After=local-fs.target multi-user.target Wants=local-fs.target [Service] Type=simple User=root Environment=TERM=linux
Si el conector HDMI cambia (p.ej.HDMI-A-2), ajusta--drm-connector=.
G) Raspberry Pi — Servicio listener TCP (nc → wrapper)
Archivo: /etc/systemd/system/recibir_rom.service
sudo tee /etc/systemd/system/recibir_rom.service >/dev/null <<'EOF'
[Unit]
Description=Persistent mpv for marquee display (DRM/KMS + IPC)
After=local-fs.target multi-user.target
Wants=local-fs.target
[Service]
Type=simple
User=root
Environment=TERM=linux
# Espera "best effort" a /dev/dri y /dev/tty1 (no falla si no están)
ExecStartPre=/bin/sh -c 'for i in $(seq 1 50); do [ -e /dev/dri/card0 ] && [ -c>
# Cambia a VT1 si existe chvt
ExecStartPre=/bin/sh -c 'if command -v chvt >/dev/null 2>&1; then chvt 1 || tru>
# Limpia socket previo
ExecStartPre=/bin/rm -f /run/mpv-marquee.sock
# ¡OJO! Ajusta el conector si no es HDMI-A-1
ExecStart=/usr/bin/mpv \
--no-config --no-terminal \
--fs --vo=drm --hwdec=auto --no-audio \
--image-display-duration=inf --keep-open=yes \
--idle=yes \
--input-ipc-server=/run/mpv-marquee.sock \
--drm-connector=HDMI-A-1 -v
# 1) Permisos al socket cuando aparezca (hasta 5 s)
ExecStartPost=/bin/sh -c 'for i in $(seq 1 50); do [ -S /run/mpv-marquee.sock ]>
# 2) Cargar el logo en cuanto el socket esté disponible (espera hasta 60 s)
ExecStartPost=/bin/sh -c '\
for i in $(seq 1 120); do \
[ -S /run/mpv-marquee.sock ] && break; \
sleep 0.5; \
done; \
/usr/local/bin/mostrar_rom_ipc.sh logo || true \
'
StandardOutput=journal
StandardError=journal
Restart=always
RestartSec=0.2
[Install]
WantedBy=multi-user.target
H) Windows/RetroBat — Instala el plugin Marquee Manager
-
Abre RetroBat
-
Ve a Updates & downloads → Content downloads → Medias & Tools → Marquee Manager y descárgalo/instálalo.
-
Verifica que exista la carpeta:
C:\RetroBat\plugins\MarqueeManager\
I) Windows/RetroBat — config.ini del plugin
Archivo: C:\RetroBat\plugins\MarqueeManager\config.ini
(Este es un ejemplo funcional completo; pégalo tal cual. Si usas otro ScreenNumber, cámbialo.)
[Settings]
Language = en
MarqueeWidth = 1920
MarqueeHeight = 480
MarqueeBorder = 0
MarqueeBackgroundColor = Black
MarqueeBackgroundCodeColor = #000000
MarqueeWhiteTextAlternativNameSuffix = -w
MarqueeAutoConvert = false
MarqueeAutoGeneration = false
MarqueeCompose = false
MarqueeMameOutput = true
MarqueeSupermodelOutput = true
MarqueeRetroAchievements = true
MarqueePinballDMD = true
MarqueeAutoScraping = false
MarqueeAutoScrapingDebug = false
ActiveDMD = false
ActiveSystemsDMD = fpinball, pinballfx, pinballfx2, pinballfx3, pinballfm, vpinball, zaccariapinball
ESCloseAllIfStop = true
AcceptedFormats = mp4, gif, jpg, png
#RetroBatPath = C:\RetroBat\
#RomsPath = C:\RetroBat\roms\
#DefaultImagePath = C:\RetroBat\plugins\MarqueeManager\images\default.png
MarqueeImagePath = C:\RetroBat\plugins\MarqueeManager\images\
MarqueeFilePath = {system_name}\{game_name}
#MarqueeImagePathDefault = C:\RetroBat\roms\
MarqueeFilePathDefault = {system_name}\images\{game_name}-marquee
FanartSystemFilePath = {system_name}
FanartGameFilePath = {system_name}\images\{game_name}-fanart
#SystemMarqueePath = C:\RetroBat\emulationstation\.emulationstation\themes\es-theme-carbon\art\logos
SystemFilePath = {system_name}
#CollectionMarqueePath = C:\RetroBat\emulationstation\.emulationstation\themes\es-theme-carbon\art\logos
CollectionFilePath = auto-{collection_name}
CollectionAlternativNames = custom-, arcade
CollectionCorrelation = recent:lastplayed, all:allgames, 2players:at2players, 4players:at4players, collections:custom-collections
IPCChannel = \\.\pipe\mpv-pipe
IPCChannelDMD = \\.\pipe\dmd-pipe
ScreenNumber = 1
MPVPath = C:\RetroBat\plugins\MarqueeManager\mpv\mpv.exe
MPVLaunchCommand = "{MPVPath}" "{DefaultImagePath}" --script=ra.lua --no-taskbar-progress --input-gamepad=yes --no-osc --loop-file=inf --alpha=yes --no-audio --no-input-cursor --no-input-default-bindings --idle --player-operation-mode=pseudo-gui --fs --fs-screen={ScreenNumber} --background={MarqueeBackgroundCodeColor} --screen={ScreenNumber} --keep-open=yes --input-ipc-server={IPCChannel} --geometry=1920x480 --no-keepaspect
#MPVLaunchCommand = "{MPVPath}" "{DefaultImagePath}" --script=ra.lua --no-taskbar-progress --input-gamepad=yes --no-osc --loop-file=inf --alpha=yes --no-audio --no-input-cursor --no-input-default-bindings --idle --player-operation-mode=pseudo-gui --fs --fs-screen={ScreenNumber} --background={MarqueeBackgroundCodeColor} --screen={ScreenNumber} --keep-open=yes --input-ipc-server={IPCChannel}
MPVKillCommand = taskkill /IM mpv.exe /F
MPVTestCommand = echo get_property idle>{IPCChannel}
MPVShowText = echo show-text '{message}'>{IPCChannel}
MPVPushRetroAchievementsDatas = echo {"command":["script-message","push-ra","{data}"]}>{IPCChannel}
IMPath = C:\RetroBat\plugins\MarqueeManager\imagemagick\convert.exe
IMConvertCommand = {IMPath} -background {MarqueeBackgroundColor} -alpha background -size x{MarqueeHeightBorderLess} -gravity center "{ImgPath}" -interpolate nearest-neighbor -geometry {MarqueeWidthBorderLess}x{MarqueeHeightBorderLess} -gravity center -extent {MarqueeWidth}x{MarqueeHeight} "{ImgTargetPath}"
IMConvertCommandMarqueeGen = {IMPath} "{FanartPath}" -resize {MarqueeWidth}x -gravity {FanartGravity} -background {MarqueeBackgroundColor} -extent {MarqueeWidth}x{MarqueeHeight}+0+{DecyOffset} "{IntermediateImgPath}"
IMConvertCommandMarqueeGenGradientLogo = {IMPath} "{IntermediateImgPath}" "{GradientPath}" -antialias -filter Lanczos -resize {LogoMaxWidth}x{LogoMaxHeight}^> -gravity {GradientGravity} -geometry {GradientPosition} -composite "{IntermediateImgPath}"
IMConvertCommandMarqueeGenLogo = {IMPath} "{IntermediateImgPath}" "{LogoPath}" -antialias -filter Lanczos -resize {LogoMaxWidth}x{LogoMaxHeight}^> -gravity {LogoGravity} -geometry {LogoPosition} -composite "{ImgTargetPath}"
IMConvertCommandSVG = {IMPath} -background {MarqueeBackgroundColor} -alpha background -size {MarqueeWidthBorderLess}^>x{MarqueeHeightBorderLess} -gravity center "{ImgPath}" -interpolate nearest-neighbor -geometry {MarqueeWidthBorderLess}x{MarqueeHeightBorderLess} -gravity center -extent {MarqueeWidth}x{MarqueeHeight} "{ImgTargetPath}"
logFile = false
[Commands]
quit = taskkill /IM mpv.exe /F
reboot = echo Rebooting
shutdown = echo Shutdown
config-changed = echo Config changed
controls-changed = echo Controls changed
settings-changed = echo Settings changed
theme-changed = echo Theme changed from "{old_theme}" to "{new_theme}"
game-start = echo loadfile "{marquee_file}" replace>{IPCChannel}
game-end = echo End
sleep = echo Sleeping
wake = echo Waking up
screensaver-start = echo Screensaver started
screensaver-stop = echo Screensaver stopped
screensaver-game-select = echo Screensaver
system-select = echo loadfile "{marquee_file}" replace>{IPCChannel}
system-selected = echo loadfile "{marquee_file}" replace>{IPCChannel}
game-select = echo loadfile "{marquee_file}" replace>{IPCChannel}
game-selected = echo loadfile "{marquee_file}" replace>{IPCChannel}
game-forceupdate = echo loadfile "{marquee_file}" replace>{IPCChannel}
marquee-commpose = echo {"command":["script-message","change-img","{data}"]}>{IPCChannel}
marquee-pushtodmd = echo {"command":["script-message","pushtodmd-img","{data}"]}>{IPCChannel}
marquee-mame = echo {"command":["script-message","mame-action","{data}"]}>{IPCChannel}
Nota: para nuestra solución con RPi, el plugin solo nos interesa por ESEvents.exe (que generaESEvent.arg). No necesitamos que MPV se muestre en Windows; nuestro Start.bat (abajo) ya matampv.exepara evitar duplicar pantallas.
J) Windows/RetroBat — Monitor inteligente (envío a RPi)
Archivo: C:\RetroBat\plugins\MarqueeManager\marquee_monitor.bat
@echo off
title RetroBat_MarqueeMonitor
setlocal enabledelayedexpansion
REM ================== CONFIG ==================
set "ESEVENT_FILE=C:\RetroBat\plugins\MarqueeManager\ESEvent.arg"
set "NCAT_EXE=C:\Program Files (x86)\Nmap\ncat.exe"
set "RPI_IP=192.168.1.138"
set "RPI_PORT=12345"
set "LOG=C:\temp\marquee_debug.log"
REM Separador que entiende la RPi (mejor ":" para evitar problemas de pipe en CMD)
set "SEPARATOR=:"
REM ============================================
if not exist "C:\temp" mkdir "C:\temp"
set "LAST_ROM="
set "LAST_SYS="
set "LAST_COMBO="
set "CURRENT_SYSTEM="
set "INITIALIZED=0"
echo Iniciando monitor inteligente de selección (sistema + juegos)...
echo ---------------------------------------------------------------
:loop
timeout /t 1 >nul
if not exist "%ESEVENT_FILE%" goto loop
REM === Tomar la ULTIMA línea del archivo ===
set "LINE="
for /f "usebackq delims=" %%A in ("%ESEVENT_FILE%") do ( set "LINE=%%A"
)
REM =======================
REM 1) EVENTO DE JUEGO
REM =======================
echo !LINE! | findstr /I "event=game-selected" >nul
if not errorlevel 1 ( REM Extraer param2 (ruta ROM) -> 3er token separado por & for /f "tokens=3 delims=&" %%a in ("!LINE!") do ( set "ROM_PATH=%%~a" ) REM Limpiar comillas y normalizar separadores set "ROM_PATH=!ROM_PATH:"=!" set "ROM_PATH=!ROM_PATH:/=\!"
REM Nombre base sin extensión (entre comillas para conservar espacios/paréntesis) for %%F in ("!ROM_PATH!") do ( set "ROM_NAME=%%~nF" )
REM Si no tenemos CURRENT_SYSTEM aún, usar el último sistema conocido if "!CURRENT_SYSTEM!"=="" if not "!LAST_SYS!"=="" set "CURRENT_SYSTEM=!LAST_SYS!"
REM Intento extra: si sigue vacío, sacar param1=<sistema> de esta misma línea if "!CURRENT_SYSTEM!"=="" ( set "P1TMP=" for /f "tokens=1-10 delims=&" %%i in ("!LINE!") do ( for %%t in (%%i %%j %%k %%l %%m %%n %%o %%p %%q %%r) do ( echo %%t | findstr /I /B "param1=" >nul && set "P1TMP=%%t" ) ) if defined P1TMP ( for /f "tokens=2 delims==" %%u in ("!P1TMP!") do set "CURRENT_SYSTEM=%%~u" set "CURRENT_SYSTEM=!CURRENT_SYSTEM:"=!" for /f "tokens=* delims= " %%z in ("!CURRENT_SYSTEM!") do set "CURRENT_SYSTEM=%%z" ) )
REM Debug echo [%time%] Juego detectado: ROM="!ROM_NAME!" SYS="!CURRENT_SYSTEM!" >> "%LOG%"
REM Inicialización: no enviamos el primer evento para evitar repeticiones en arranque if "!INITIALIZED!"=="0" ( set "LAST_ROM=!ROM_NAME!" if not "!CURRENT_SYSTEM!"=="" set "LAST_SYS=!CURRENT_SYSTEM!" set "LAST_COMBO=!CURRENT_SYSTEM!!SEPARATOR!!ROM_NAME!" set "INITIALIZED=1" echo [%time%] Inicializado con COMBO: !LAST_COMBO! >> "%LOG%" goto loop )
if "!ROM_NAME!"=="" goto loop if "!CURRENT_SYSTEM!"=="" ( echo [%time%] Aviso: sin sistema resuelto para la ROM "!ROM_NAME!", no se envía. >> "%LOG%" goto loop )
set "COMBO=!CURRENT_SYSTEM!!SEPARATOR!!ROM_NAME!" if /I "!COMBO!"=="!LAST_COMBO!" goto loop
echo [%time%] Enviando COMBO !COMBO! a la Raspberry Pi... >> "%LOG%" echo "!COMBO!" | "!NCAT_EXE!" %RPI_IP% %RPI_PORT%
set "LAST_ROM=!ROM_NAME!" set "LAST_SYS=!CURRENT_SYSTEM!" set "LAST_COMBO=!COMBO!" goto loop
)
REM =======================
REM 2) EVENTO DE SISTEMA
REM (admite system-selected y system-changed)
REM =======================
echo !LINE! | findstr /I "event=system-selected event=system-changed" >nul
if not errorlevel 1 ( REM param1="nombre_del_sistema" -> 2º token separado por & for /f "tokens=2 delims=&" %%a in ("!LINE!") do ( set "SYS_KV=%%~a" ) for /f "tokens=2 delims==" %%b in ("!SYS_KV!") do ( set "SYSTEM_RAW=%%~b" ) REM Quitar comillas y recortar espacios iniciales set "SYSTEM=!SYSTEM_RAW:"=!" for /f "tokens=* delims= " %%z in ("!SYSTEM!") do set "SYSTEM=%%z"
REM Debug echo [%time%] Sistema detectado: "!SYSTEM!" >> "%LOG%"
if "!INITIALIZED!"=="0" ( set "CURRENT_SYSTEM=!SYSTEM!" set "LAST_SYS=!SYSTEM!" set "INITIALIZED=1" echo [%time%] Inicializado con SISTEMA: !SYSTEM! >> "%LOG%" goto loop )
if "!SYSTEM!"=="" goto loop if /I "!SYSTEM!"=="!LAST_SYS!" goto loop
echo [%time%] Enviando SISTEMA !SYSTEM! a la Raspberry Pi... >> "%LOG%" echo "!SYSTEM!" | "!NCAT_EXE!" %RPI_IP% %RPI_PORT%
set "CURRENT_SYSTEM=!SYSTEM!" set "LAST_SYS=!SYSTEM!" REM opcional: resetea combo al cambiar de sistema set "LAST_COMBO=" goto loop
)
goto loop
K) Windows/RetroBat — Start.bat del plugin (sustituye al lanzamiento “Start.exe”)
Archivo: C:\RetroBat\plugins\MarqueeManager\Start.bat
Uso recomendado: en lugar de abrir Start.exe del plugin, ejecuta esteStart.bat. Si quieres, renombra elStart.exeoriginal aStart.exe.bakpara no usarlo por error.
@echo off setlocal enabledelayedexpansion :: === CONFIGURAR RUTA Y TÍTULO DEL MONITOR === set "MONITOR_BAT=C:\RetroBat\plugins\MarqueeManager\marquee_monitor.bat" set "MONITOR_TITLE=RetroBat_MarqueeMonitor" cd /d "%~dp0" :: --- Cerrar procesos de RetroBat previos (incluye mpv para no duplicar pantalla en Windows) --- for %%P in ( ESEvents.exe ESEventsScrapTopper.exe ESRetroAchievements.exe VPListenerWS.exe MAMEListenerWS.exe SUPERMODELListenerWS.exe retroarch.exe mpv.exe dmd.exe emulationstation.exe ) do ( tasklist | find /I "%%P" > NUL && taskkill /IM %%P /F ) :: --- Limpiar tmp del MarqueeManager --- rd /s /q ".\.tmp" 2>NUL :: === INICIAR EL MONITOR EN CONSOLA PROPIA === start "%MONITOR_TITLE%" cmd /k ""%MONITOR_BAT%"" :: --- Iniciar ESEvents.exe (genera ESEvent.arg que lee el monitor) --- start "" ESEvents.exe timeout /t 1 /nobreak >NUL :: --- Iniciar RetroBat --- start "" ..\..\retrobat.exe timeout /t 2 /nobreak >NUL :: === Vigilar hasta que RetroBat se cierre === :wait_rb tasklist | find /I "retrobat.exe" >NUL if not errorlevel 1 ( timeout /t 2 >NUL goto wait_rb ) tasklist | find /I "emulationstation.exe" >NUL if not errorlevel 1 ( timeout /t 2 >NUL goto wait_rb ) :: === CERRAR EL MONITOR === taskkill /FI "WINDOWTITLE eq %MONITOR_TITLE%" /T /F >NUL 2>&1 endlocal
L) Dónde van las imágenes/vídeos
-
RPi (nuestro flujo actual):
-
ROMs:
/home/arcade/<sistema>/<rom>.(mp4|gif|jpg|png)
Ej.:/home/arcade/megadrive/FIFA International Soccer (USA, Europe).mp4 -
Sistemas:
/home/arcade/sistemas/<sistema>.(mp4|gif|jpg|png) -
Fallback logo:
/home/arcade/default/logo.(mp4|gif|jpg|png)
-
-
Windows (solo si quisieras usar mpv del plugin):
C:\RetroBat\plugins\MarqueeManager\images\<sistema>\...
(No es necesario para nuestro flujo con RPi.)
M) Activación y pruebas
En la RPi:
sudo systemctl daemon-reload sudo systemctl enable --now marquee-mpv.service recibir_rom.service systemctl status marquee-mpv.service --no-pager systemctl status recibir_rom.service --no-pager ls -l /run/mpv-marquee.sock tail -n 50 /home/arcade/recibir_rom.log tail -n 100 /home/arcade/mostrar_rom_debug.log
En Windows (CMD):
REM Pruebas directas al listener echo "mame:1942" | "C:\Program Files (x86)\Nmap\ncat.exe" 192.168.1.138 12345 echo "vertical:1942" | "C:\Program Files (x86)\Nmap\ncat.exe" 192.168.1.138 12345 echo "megadrive:FIFA International Soccer (USA|v Europe)" | "C:\Program Files (x86)\Nmap\ncat.exe" 192.168.1.138 12345 echo "all:FIFA International Soccer (USA|v Europe)" | "C:\Program Files (x86)\Nmap\ncat.exe" 192.168.1.138 12345 echo "logo" | "C:\Program Files (x86)\Nmap\ncat.exe" 192.168.1.138 12345
Lanzamiento normal desde Windows:
-
Ejecuta
C:\RetroBat\plugins\MarqueeManager\Start.bat
(Este arrancaESEvents.exe, tu monitor y RetroBat; matampv.exepara no duplicar).
¡Listo!
Con esto queda:
-
RPi: mpv (DRM/KMS) + socket IPC, listener TCP y wrapper con alias/búsqueda global.
-
Windows/RetroBat: plugin instalado, config.ini completo, monitor que envía a la RPi y Start.bat que sustituye al Start.exe del plugin.
-
Soporte de mp4 + gif + jpg + png, normalización de nombres conflictivos (ej.
|v → ,) y colecciones (alias + búsqueda global).
SrRubio
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.