From 50036f9bacd077b73a33a275cc92ecedfe5ac50c Mon Sep 17 00:00:00 2001 From: "david.schkalee" Date: Tue, 14 Jul 2026 19:29:12 +0200 Subject: [PATCH] Add RAOfflineProxy integration: service file and launch-time RetroArch proxy routing --- Config.in | 1 + configs/knulli-board.common | 1 + .../generators/libretro/libretroConfig.py | 29 ++++++++++ package/system/raofflineproxy/Config.in | 11 ++++ .../system/raofflineproxy/raofflineproxy.mk | 16 +++++ .../raofflineproxy/services/raofflineproxy | 58 +++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 package/system/raofflineproxy/Config.in create mode 100644 package/system/raofflineproxy/raofflineproxy.mk create mode 100755 package/system/raofflineproxy/services/raofflineproxy diff --git a/Config.in b/Config.in index e2cbc00e..11599f04 100644 --- a/Config.in +++ b/Config.in @@ -717,6 +717,7 @@ menu "Knulli Packages" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-resolution/Config.in" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-scripts/Config.in" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-settings/Config.in" + source "$BR2_EXTERNAL_KNULLI_PATH/package/system/raofflineproxy/Config.in" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-bluetooth/Config.in" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-audio/Config.in" source "$BR2_EXTERNAL_KNULLI_PATH/package/system/knulli-audio-alsa/Config.in" diff --git a/configs/knulli-board.common b/configs/knulli-board.common index acfdf53f..20de31bd 100644 --- a/configs/knulli-board.common +++ b/configs/knulli-board.common @@ -92,6 +92,7 @@ BR2_PACKAGE_MOSQUITTO_BROKER=n # System BR2_PACKAGE_KNULLI_SYSTEM=y +BR2_PACKAGE_RAOFFLINEPROXY=y BR2_PACKAGE_BATOCERA_EXTRAS=y BR2_PACKAGE_BATOCERA_TOOLS=y BR2_PACKAGE_BATOCERA_ALL_SYSTEMS=y diff --git a/package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroConfig.py b/package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroConfig.py index 02cac4ed..05248953 100644 --- a/package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroConfig.py +++ b/package/system/knulli-configgen/configgen/configgen/generators/libretro/libretroConfig.py @@ -917,6 +917,35 @@ def apply_tate_profile(retroarchConfig, rotation, remap): else: retroarchConfig['cheevos_enable'] = 'false' + # RAOfflineProxy: when the proxy service is listening and not disabled via + # retroachievements.proxy, route RetroAchievements through it. The proxy + # serves cached data offline, so cheevos stays enabled without internet. + # Casual-only by design: hardcore is forced off while routing through it. + try: + raop_port = 8080 + try: + import json as raop_json + with open('/userdata/system/.config/raofflineproxy/config.json') as raop_fh: + raop_port = int(raop_json.load(raop_fh).get('proxy_port', 8080)) + except Exception: + pass + import socket as raop_socket + raop_sock = raop_socket.socket(raop_socket.AF_INET, raop_socket.SOCK_STREAM) + raop_sock.settimeout(0.25) + raop_running = raop_sock.connect_ex(('127.0.0.1', raop_port)) == 0 + raop_sock.close() + raop_wanted = system.isOptSet('retroachievements') and system.getOptBoolean('retroachievements') == True + raop_core_ok = (system.config['core'] in coreToRetroachievements) or (system.isOptSet('cheevos_force') and system.getOptBoolean('cheevos_force') == True) + raop_proxy_on = (not system.isOptSet('retroachievements.proxy')) or (system.getOptBoolean('retroachievements.proxy') == True) + if raop_running and raop_wanted and raop_core_ok and raop_proxy_on: + retroarchConfig['cheevos_enable'] = 'true' + retroarchConfig['cheevos_custom_host'] = '127.0.0.1:%s' % raop_port + retroarchConfig['cheevos_hardcore_mode_enable'] = 'false' + else: + retroarchConfig['cheevos_custom_host'] = '' + except Exception: + retroarchConfig['cheevos_custom_host'] = '' + if system.isOptSet('integerscale') and system.getOptBoolean('integerscale') == True: retroarchConfig['video_scale_integer'] = 'true' else: diff --git a/package/system/raofflineproxy/Config.in b/package/system/raofflineproxy/Config.in new file mode 100644 index 00000000..53089013 --- /dev/null +++ b/package/system/raofflineproxy/Config.in @@ -0,0 +1,11 @@ +config BR2_PACKAGE_RAOFFLINEPROXY + bool "raofflineproxy" + + help + System integration for RAOfflineProxy, an offline proxy for + RetroAchievements (offline achievement caching and casual unlock + queueing). Ships the service file so the proxy can be toggled in + EmulationStation. The app itself installs to /userdata via the + RAOfflineProxy installer; the service is a no-op without it. + + https://github.com/misantronic/RAOfflineProxy diff --git a/package/system/raofflineproxy/raofflineproxy.mk b/package/system/raofflineproxy/raofflineproxy.mk new file mode 100644 index 00000000..d01a2497 --- /dev/null +++ b/package/system/raofflineproxy/raofflineproxy.mk @@ -0,0 +1,16 @@ +################################################################################ +# +# raofflineproxy +# +################################################################################ + +RAOFFLINEPROXY_VERSION = 1.0 +RAOFFLINEPROXY_LICENSE = GPL-3.0 +RAOFFLINEPROXY_SOURCE = + +define RAOFFLINEPROXY_INSTALL_TARGET_CMDS + $(INSTALL) -D -m 0755 $(BR2_EXTERNAL_KNULLI_PATH)/package/system/raofflineproxy/services/raofflineproxy \ + $(TARGET_DIR)/usr/share/knulli/services/raofflineproxy +endef + +$(eval $(generic-package)) diff --git a/package/system/raofflineproxy/services/raofflineproxy b/package/system/raofflineproxy/services/raofflineproxy new file mode 100755 index 00000000..127f94ef --- /dev/null +++ b/package/system/raofflineproxy/services/raofflineproxy @@ -0,0 +1,58 @@ +#!/bin/bash + +LAUNCHER=/userdata/system/raofflineproxy/bin/raofflineproxy +PIDFILE=/var/run/raofflineproxy-service.pid + +start() { + echo -n "Starting raofflineproxy: " + if [ ! -x "${LAUNCHER}" ]; then + echo "failed (app not installed at ${LAUNCHER})" + return 1 + fi + start-stop-daemon -S -b -q -m -p "${PIDFILE}" --exec "${LAUNCHER}" -- run-service + RETVAL=$? + echo "done" + return ${RETVAL} +} + +stop() { + echo -n "Stopping raofflineproxy: " + start-stop-daemon -K -q -p "${PIDFILE}" + RETVAL=$? + rm -f "${PIDFILE}" + echo "done" + return ${RETVAL} +} + +status() { + if start-stop-daemon --status -q -p "${PIDFILE}"; then + echo "started" + else + echo "stopped" + fi +} + +restart() { + stop + start +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart) + restart + ;; + *) + echo "Usage: $0 {start|stop|status|restart}" + ;; +esac + +exit $?