Merge pull request #437 from outis1one/claude/wolf-pair-port-conflict-7nz8qg

wolf: make ES-DE RunInBackground fix fully self-healing, no manual step
This commit is contained in:
Outis
2026-09-03 14:40:09 -04:00
committed by GitHub
+216 -44
View File
@@ -325,8 +325,8 @@ EOF
echo " and Wii U (Cemu) in ES-DE via a second, opt-in 'Alternative emulators' command" echo " and Wii U (Cemu) in ES-DE via a second, opt-in 'Alternative emulators' command"
echo " - Expose Wolf's REST API socket to the host (WOLF_SOCKET_PATH + /var/run/wolf mount)" echo " - Expose Wolf's REST API socket to the host (WOLF_SOCKET_PATH + /var/run/wolf mount)"
echo " so './manage.sh controllers' can force distinct pad types per controller slot" echo " so './manage.sh controllers' can force distinct pad types per controller slot"
echo " - Mount ~/ES-DE/settings durably + force 'Run in background' off (only once" echo " - Mount ~/ES-DE/settings durably + force 'Run in background' off automatically"
echo " GOW's own es_settings.xml template already exists — never pre-created)" echo " (self-healing — writes GOW's real template if missing/broken, no manual step)"
return 0 return 0
fi fi
@@ -1393,7 +1393,7 @@ PS2XMLPY
log_success "PS2: added PCEE2 as the default RetroArch core (custom_systems/es_systems.xml) — ES-DE's" log_success "PS2: added PCEE2 as the default RetroArch core (custom_systems/es_systems.xml) — ES-DE's"
log_info "own build doesn't ship it yet (added upstream in the not-yet-released 3.5.0)" log_info "own build doesn't ship it yet (added upstream in the not-yet-released 3.5.0)"
# ── ES-DE: force "Run in background" off (once GOW's own template exists) ── # ── ES-DE: force "Run in background" off (self-healing, no manual step) ──
# GOW's own image bakes a FULL es_settings.xml template (100+ settings — # GOW's own image bakes a FULL es_settings.xml template (100+ settings —
# confirmed against apps/es-de/build/configs/es/es_settings.xml in the # confirmed against apps/es-de/build/configs/es/es_settings.xml in the
# games-on-whales/gow repo) that deliberately sets RunInBackground=true # games-on-whales/gow repo) that deliberately sets RunInBackground=true
@@ -1410,39 +1410,212 @@ PS2XMLPY
# ROMDirectory (GOW's template sets it to the /ROMs this whole repo # ROMDirectory (GOW's template sets it to the /ROMs this whole repo
# mounts games at; ES-DE's own default is not that). # mounts games at; ES-DE's own default is not that).
# #
# CONFIRMED LIVE, THE HARD WAY: an earlier version of this exact step # CONFIRMED LIVE, THE HARD WAY (twice): an earlier version of this step
# pre-created a MINIMAL stub file (containing only the RunInBackground # pre-created a MINIMAL stub file before the container had ever started,
# line) before the container had ever started — GOW's startup.sh saw # which made GOW skip its own copy and broke ROM discovery on every
# that file "already existing", skipped its own copy, and ES-DE's # system. A second attempt only ever patched an ALREADY non-empty file
# ROMDirectory silently fell back to a default that isn't /ROMs, finding # and left a pre-existing broken stub (or a genuinely missing file)
# zero games on every single system. Root-caused by walking GOW's own # alone, requiring a manual "connect once via Moonlight, then re-run
# startup.sh line by line against a real "ES-DE finds no game files" # setup" step — exactly the manual dependency this version removes. This
# report. Never pre-create this file — only ever patch an ALREADY # embeds GOW's own real template verbatim (fetched directly from
# existing one (i.e. one GOW's own bootstrap has already populated in # games-on-whales/gow:apps/es-de/build/configs/es/es_settings.xml, with
# full, meaning ES-DE has been launched via Moonlight at least once). # only RunInBackground flipped true→false) and writes it whenever the
# on-disk file is missing OR is that same broken stub — detected by the
# absence of the ROMDirectory key, which only a real GOW-written or
# ES-DE-written file ever has — so this fix now works unconditionally,
# regardless of whether ES-DE has ever actually launched, with no
# dependency on connection order.
mkdir -p "$GAME_STORAGE_DIR/esde-settings" mkdir -p "$GAME_STORAGE_DIR/esde-settings"
_ESDE_SETTINGS="$GAME_STORAGE_DIR/esde-settings/es_settings.xml" _ESDE_SETTINGS="$GAME_STORAGE_DIR/esde-settings/es_settings.xml"
if [ -s "$_ESDE_SETTINGS" ]; then
backup_if_exists "$_ESDE_SETTINGS" backup_if_exists "$_ESDE_SETTINGS"
python3 - "$_ESDE_SETTINGS" << 'ESDESETTINGSPY' python3 - "$_ESDE_SETTINGS" << 'ESDESETTINGSPY'
import re, sys import re, sys
path = sys.argv[1] path = sys.argv[1]
with open(path) as f: try:
with open(path) as f:
content = f.read() content = f.read()
content = re.sub(r'[ \t]*<bool name="RunInBackground" value="[^"]*"[ \t]*/>[ \t]*\n?', '', content) except FileNotFoundError:
line = '<bool name="RunInBackground" value="false" />\n' content = ''
content = content.rstrip('\n') + '\n' + line
GOW_ESDE_SETTINGS_TEMPLATE = """<?xml version="1.0"?>
<bool name="AlternativeEmulatorPerGame" value="true" />
<bool name="ApplicationUpdaterPrereleases" value="false" />
<bool name="CreatePlaceholderSystemDirectories" value="false" />
<bool name="CustomEventScripts" value="false" />
<bool name="DebugMode" value="false" />
<bool name="DebugSkipInputLogging" value="false" />
<bool name="DebugSkipMissingThemeFiles" value="false" />
<bool name="DebugSkipMissingThemeFilesCustomCollections" value="true" />
<bool name="DisableComposition" value="false" />
<bool name="DisplayGPUStatistics" value="false" />
<bool name="EnableMenuKidMode" value="false" />
<bool name="FavFirstCustom" value="false" />
<bool name="FavStarCustom" value="false" />
<bool name="FavoritesAddButton" value="true" />
<bool name="FavoritesFirst" value="true" />
<bool name="FavoritesStar" value="true" />
<bool name="FoldersOnTop" value="true" />
<bool name="GamelistFilters" value="true" />
<bool name="GamelistVideoPillarbox" value="true" />
<bool name="GamelistVideoScanlines" value="false" />
<bool name="HideTaskbar" value="false" />
<bool name="InputIgnoreKeyboard" value="false" />
<bool name="InputOnlyFirstController" value="false" />
<bool name="InputSwapButtons" value="false" />
<bool name="LegacyGamelistFileLocation" value="false" />
<bool name="ListScrollOverlay" value="false" />
<bool name="MAMENameStripExtraInfo" value="true" />
<bool name="MediaViewerKeepVideoRunning" value="true" />
<bool name="MediaViewerScreenshotScanlines" value="true" />
<bool name="MediaViewerShowTypes" value="false" />
<bool name="MediaViewerStretchVideos" value="false" />
<bool name="MediaViewerVideoAudio" value="true" />
<bool name="MediaViewerVideoBlur" value="false" />
<bool name="MediaViewerVideoScanlines" value="true" />
<bool name="MenuBlurBackground" value="true" />
<bool name="MiximageCoverFallback" value="true" />
<bool name="MiximageGenerate" value="true" />
<bool name="MiximageIncludeBox" value="true" />
<bool name="MiximageIncludeMarquee" value="true" />
<bool name="MiximageIncludePhysicalMedia" value="true" />
<bool name="MiximageOverwrite" value="true" />
<bool name="MiximageRemoveLetterboxes" value="true" />
<bool name="MiximageRemovePillarboxes" value="true" />
<bool name="MiximageRotateHorizontalBoxes" value="true" />
<bool name="NavigationSounds" value="true" />
<bool name="ParseGamelistOnly" value="false" />
<bool name="RunInBackground" value="false" />
<bool name="Scrape3DBoxes" value="true" />
<bool name="ScrapeBackCovers" value="true" />
<bool name="ScrapeCovers" value="true" />
<bool name="ScrapeFanArt" value="true" />
<bool name="ScrapeGameNames" value="true" />
<bool name="ScrapeManuals" value="true" />
<bool name="ScrapeMarquees" value="true" />
<bool name="ScrapeMetadata" value="true" />
<bool name="ScrapePhysicalMedia" value="true" />
<bool name="ScrapeRatings" value="true" />
<bool name="ScrapeScreenshots" value="true" />
<bool name="ScrapeTitleScreens" value="true" />
<bool name="ScrapeVideos" value="true" />
<bool name="ScraperAutomaticRemoveDots" value="true" />
<bool name="ScraperConvertUnderscores" value="true" />
<bool name="ScraperExcludeRecursively" value="true" />
<bool name="ScraperHaltOnInvalidMedia" value="true" />
<bool name="ScraperIgnoreHTTP404Errors" value="true" />
<bool name="ScraperIncludeFolders" value="true" />
<bool name="ScraperInteractive" value="false" />
<bool name="ScraperOverwriteData" value="false" />
<bool name="ScraperRegionFallback" value="true" />
<bool name="ScraperRespectExclusions" value="true" />
<bool name="ScraperSearchFileHash" value="true" />
<bool name="ScraperSearchMetadataName" value="true" />
<bool name="ScraperSemiautomatic" value="true" />
<bool name="ScraperUseAccountScreenScraper" value="true" />
<bool name="ScreensaverControls" value="true" />
<bool name="ScreensaverSlideshowCustomImages" value="false" />
<bool name="ScreensaverSlideshowGameInfo" value="true" />
<bool name="ScreensaverSlideshowOnlyFavorites" value="false" />
<bool name="ScreensaverSlideshowRecurse" value="false" />
<bool name="ScreensaverSlideshowScanlines" value="true" />
<bool name="ScreensaverStretchImages" value="false" />
<bool name="ScreensaverStretchVideos" value="false" />
<bool name="ScreensaverVideoAudio" value="true" />
<bool name="ScreensaverVideoBlur" value="false" />
<bool name="ScreensaverVideoGameInfo" value="true" />
<bool name="ScreensaverVideoOnlyFavorites" value="false" />
<bool name="ScreensaverVideoScanlines" value="true" />
<bool name="ShowHelpPrompts" value="true" />
<bool name="ShowHiddenFiles" value="true" />
<bool name="ShowHiddenGames" value="true" />
<bool name="ShowQuitMenu" value="false" />
<bool name="ThemeVariantTriggers" value="true" />
<bool name="VideoUpscaleFrameRate" value="false" />
<bool name="ViewsVideoAudio" value="true" />
<bool name="VirtualKeyboard" value="true" />
<int name="AntiAliasing" value="0" />
<int name="ApplicationRelease" value="46" />
<int name="DisplayIndex" value="1" />
<int name="LottieMaxFileCache" value="150" />
<int name="LottieMaxTotalCache" value="1024" />
<int name="MaxVRAM" value="512" />
<int name="ScraperConnectionTimeout" value="30" />
<int name="ScraperRetryOnErrorCount" value="2" />
<int name="ScraperRetryOnErrorTimer" value="2" />
<int name="ScraperSearchFileHashMaxSize" value="384" />
<int name="ScraperTransferTimeout" value="120" />
<int name="ScreenRotate" value="0" />
<int name="ScreensaverSwapImageTimeout" value="10000" />
<int name="ScreensaverSwapVideoTimeout" value="0" />
<int name="ScreensaverTimer" value="300000" />
<int name="SoundVolumeNavigation" value="70" />
<int name="SoundVolumeVideos" value="80" />
<string name="ApplicationLanguage" value="automatic" />
<string name="ApplicationUpdaterDownloadDirectory" value="" />
<string name="ApplicationUpdaterFrequency" value="always" />
<string name="ApplicationUpdaterLastCheck" value="20230516T185718" />
<string name="ApplicationVersion" value="2.0.1" />
<string name="CollectionCustomGrouping" value="unthemed" />
<string name="CollectionSystemsAuto" value="" />
<string name="CollectionSystemsCustom" value="" />
<string name="DefaultSortOrder" value="name, ascending" />
<string name="GamelistViewStyle" value="automatic" />
<string name="InputControllerType" value="ps4" />
<string name="KeyboardQuitShortcut" value="AltF4" />
<string name="LaunchScreenDuration" value="normal" />
<string name="LegacyThemeTransitions" value="builtin-instant" />
<string name="MediaDirectory" value="/media" />
<string name="MediaViewerHelpPrompts" value="top" />
<string name="MenuColorScheme" value="dark" />
<string name="MenuOpeningEffect" value="scale-up" />
<string name="MiximageBoxSize" value="medium" />
<string name="MiximagePhysicalMediaSize" value="medium" />
<string name="MiximageResolution" value="1280x960" />
<string name="MiximageScreenshotAspectThreshold" value="high" />
<string name="MiximageScreenshotBlankAreasColor" value="black" />
<string name="MiximageScreenshotHorizontalFit" value="crop" />
<string name="MiximageScreenshotScaling" value="sharp" />
<string name="MiximageScreenshotVerticalFit" value="contain" />
<string name="OpenGLVersion" value="" />
<string name="QuickSystemSelect" value="leftrightshoulders" />
<string name="ROMDirectory" value="/ROMs" />
<string name="RandomEntryButton" value="games" />
<string name="SaveGamelistsMode" value="always" />
<string name="Scraper" value="thegamesdb" />
<string name="ScraperLanguage" value="ru" />
<string name="ScraperPasswordScreenScraper" value="" />
<string name="ScraperRegion" value="eu" />
<string name="ScraperUsernameScreenScraper" value="" />
<string name="ScreensaverSlideshowCustomDir" value="" />
<string name="ScreensaverSlideshowImageDir" value="~/ES-DE/slideshow/custom_images" />
<string name="ScreensaverType" value="video" />
<string name="StartupSystem" value="Custom Scripts" />
<string name="SystemsSorting" value="default" />
<string name="Theme" value="modern-es-de" />
<string name="ThemeAspectRatio" value="automatic" />
<string name="ThemeColorScheme" value="dark" />
<string name="ThemeFontSize" value="medium" />
<string name="ThemeLanguage" value="automatic" />
<string name="ThemeSet" value="" />
<string name="ThemeTransitions" value="automatic" />
<string name="ThemeVariant" value="withVideos" />
<string name="UIMode" value="full" />
<string name="UIMode_passkey" value="uuddlrlrba" />
<string name="UserThemeDirectory" value="" />
"""
if 'ROMDirectory' not in content:
content = GOW_ESDE_SETTINGS_TEMPLATE
else:
content = re.sub(r'[ \t]*<bool name="RunInBackground" value="[^"]*"[ \t]*/>[ \t]*\n?', '', content)
line = '<bool name="RunInBackground" value="false" />\n'
content = content.rstrip('\n') + '\n' + line
with open(path, 'w') as f: with open(path, 'w') as f:
f.write(content) f.write(content)
ESDESETTINGSPY ESDESETTINGSPY
chown "$ACTUAL_USER:$ACTUAL_USER" "$_ESDE_SETTINGS" chown "$ACTUAL_USER:$ACTUAL_USER" "$_ESDE_SETTINGS"
log_success "ES-DE: 'Run in background (while game is launched)' forced off (esde-settings/es_settings.xml)" log_success "ES-DE: 'Run in background (while game is launched)' forced off (esde-settings/es_settings.xml)"
else
log_info "ES-DE: 'Run in background' fix deferred — esde-settings/es_settings.xml doesn't"
log_info "exist yet (GOW writes its real, full template the first time EmulationStation"
log_info "actually launches). Connect to it via Moonlight once, then re-run"
log_info "'sudo ./setup.sh wolf' to apply this fix without touching anything else."
fi
# ── App selection ───────────────────────────────────────────────────────── # ── App selection ─────────────────────────────────────────────────────────
echo "" echo ""
@@ -4373,26 +4546,25 @@ ES-DE's own *compiled* default for this is off — but GOW's own bundled
deliberately sets it **on**, which is the actual, confirmed source of the deliberately sets it **on**, which is the actual, confirmed source of the
default behavior here. default behavior here.
**This installer forces it back off** by patching \`esde-settings/es_settings.xml\` **This installer forces it back off automatically, with no manual step.**
— but only an *already-populated* copy of that file, never by creating one It writes \`esde-settings/es_settings.xml\` directly from GOW's own real
itself. That distinction matters: GOW's own container startup script only template (100+ settings, fetched from GOW's own repo, byte-for-byte
writes its real template (100+ settings, including where ES-DE looks for identical except \`RunInBackground\` flipped to off) whenever that file is
your ROMs) the very first time EmulationStation actually launches, gated either missing or still the old broken placeholder — detected by checking
on that file not already existing — pre-creating even a minimal version of for \`ROMDirectory\`, a key only GOW's own bootstrap or ES-DE itself ever
it ourselves, before that first launch, would make GOW skip writing its writes. If the file already has a real, fully-populated value (because
own template entirely and leave ES-DE on vanilla upstream defaults for EmulationStation has already launched at least once and GOW wrote its own
everything else in that file. **Confirmed live, the hard way:** an earlier copy), only the one \`RunInBackground\` line is patched, leaving every
version of this exact fix did precisely that, and ROM discovery broke other setting (theme, scraper prefs, etc.) untouched. Either way, one
completely (every system, not just one) because ES-DE's ROM path fell \`sudo ./setup.sh wolf\` run is enough — no need to connect via Moonlight
back to something other than \`/ROMs\`. first. **Confirmed live, the hard way, twice:** earlier versions of this
fix either pre-created a minimal stub that made GOW skip writing its own
So in practice: if you've already launched EmulationStation via Moonlight template (breaking ROM discovery on every system, since the ROM path fell
at least once, re-running \`sudo ./setup.sh wolf\` applies this immediately. back to something other than \`/ROMs\`), or only patched an already-existing
**If you haven't yet** (a genuinely fresh install), the installer says so file and left a genuinely missing/broken one alone, requiring exactly the
and skips the patch rather than guessing — connect to EmulationStation manual Moonlight-connect step this version removes. Setting it by hand
once first, then re-run \`sudo ./setup.sh wolf\`. Setting it by hand works still works too, any time: **Main Menu → Other Settings → Run in
too, any time: **Main Menu → Other Settings → Run in background (while background (while game is launched) → off**.
game is launched) → off**.
**Why this needed its own mount, not just a one-time write:** \`~/ES-DE\` **Why this needed its own mount, not just a one-time write:** \`~/ES-DE\`
(settings, gamelists, scraped artwork, logs) had no bind mount onto the (settings, gamelists, scraped artwork, logs) had no bind mount onto the