From fcbd45453febad1dfa8bc8a7e122bdfcb07c71c7 Mon Sep 17 00:00:00 2001 From: K11MCH1 <81425424+K11MCH1@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:25:31 +0900 Subject: [PATCH] Steam imports: read only the linked manifest, and leave staged ones alone seed_install read the app's manifest from every library before checking that it was the linked DroidDeck install, so a manifest in another library that is not UTF-8 raised past the caller and stopped routing for later games. It now returns before reading anything but the linked manifest. An untouched manifest from an older version was migrated even while steamapps/downloading/ existed; that migration now waits until Steam is not staging the app, like the rewrite of a queued import. --- .../usr/local/bin/droiddeck-steam-games | 12 ++++++----- tools/tests/test_steam_games.py | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/tools/linuxfs/overlay/usr/local/bin/droiddeck-steam-games b/tools/linuxfs/overlay/usr/local/bin/droiddeck-steam-games index 2997444f9..c902676d3 100755 --- a/tools/linuxfs/overlay/usr/local/bin/droiddeck-steam-games +++ b/tools/linuxfs/overlay/usr/local/bin/droiddeck-steam-games @@ -461,13 +461,15 @@ def seed_install(steam_root, game, appid): for root in libraries(steam_root): existing = root / "steamapps" / manifest.name if existing.is_file(): + if not (existing == manifest and source.is_dir() and target.is_symlink() + and os.readlink(target) == str(source)): + return True text = existing.read_text() - linked = (existing == manifest and source.is_dir() and target.is_symlink() - and os.readlink(target) == str(source)) - if linked and build is None and update_not_started(text, steamapps, appid, name): + staging = (steamapps / "downloading" / str(appid)).exists() + if build is None and update_not_started(text, steamapps, appid, name): wanted = update_on_launch(text) - elif linked and (text in (minimal, bare, legacy, legacy.replace('"StateFlags" "4"', '"StateFlags" "2"')) - or (build is not None and update_not_started(text, steamapps, appid, name))): + elif ((text in (minimal, bare, legacy, legacy.replace('"StateFlags" "4"', '"StateFlags" "2"')) and not staging) + or (build is not None and update_not_started(text, steamapps, appid, name))): wanted = content else: wanted = text diff --git a/tools/tests/test_steam_games.py b/tools/tests/test_steam_games.py index ae9e1d569..16c08e142 100644 --- a/tools/tests/test_steam_games.py +++ b/tools/tests/test_steam_games.py @@ -336,6 +336,27 @@ class ImportsTest(unittest.TestCase): imports.route(self.steam, self.acct, [self.game]) self.assertEqual(before, path.read_text()) + def test_an_untouched_import_is_left_alone_while_steam_stages_it(self): + self.snapshot() + imports.route(self.steam, self.acct, [self.game]) + path = self.steam / 'steamapps/appmanifest_42.acf' + older = path.read_text().replace(' "AutoUpdateBehavior" "1"\n', '') + path.write_text(older) + (self.steam / 'steamapps/downloading/42').mkdir(parents=True) + imports.route(self.steam, self.acct, [self.game]) + self.assertEqual(older, path.read_text()) + + def test_a_manifest_in_another_library_is_not_read(self): + other = self.root / 'Other' + (other / 'steamapps').mkdir(parents=True) + (other / 'steamapps/appmanifest_42.acf').write_bytes(b'"AppState"\n{\n "name" "\xff\xfe"\n}\n') + (self.steam / 'steamapps').mkdir(parents=True) + (self.steam / 'steamapps/libraryfolders.vdf').write_text('"libraryfolders"\n{\n\t"1"\n\t{\n\t\t"path"\t\t"%s"\n\t}\n}\n' % other) + self.snapshot() + games, routes = imports.route(self.steam, self.acct, [self.game]) + self.assertEqual({str(self.game['appid']): 42}, routes) + self.assertEqual(b'"AppState"\n{\n "name" "\xff\xfe"\n}\n', (other / 'steamapps/appmanifest_42.acf').read_bytes()) + def test_started_import_without_a_build_is_left_to_steam(self): for extra, staging in [('\t"BytesDownloaded"\t\t"5"\n\t"AutoUpdateBehavior"\t\t"0"\n', False), ('\t"AutoUpdateBehavior"\t\t"0"\n', True)]: