mirror of
https://github.com/ClassicWasTaken/HaloCE-SteamFrame.git
synced 2026-10-17 17:00:36 +02:00
Merge contributed renamed-shortcut fix from PR #8
This commit is contained in:
commit
0aba1aa2b5
2 files changed
+52
-5
No files matched your search
@@ -312,7 +312,7 @@ def update_shortcut(data: bytes | None, executable: str, directory: str) -> tupl
|
||||
|
||||
|
||||
def remove_shortcut(data: bytes, executable: str) -> tuple[bytes, list[int]]:
|
||||
"""Remove only exact native title/path matches; keep all foreign fields."""
|
||||
"""Remove only entries that launch the native executable; keep all foreign fields."""
|
||||
root = loads(data)
|
||||
shortcuts = root.get("shortcuts")
|
||||
if shortcuts is None or shortcuts.kind != 0:
|
||||
@@ -322,13 +322,17 @@ def remove_shortcut(data: bytes, executable: str) -> tuple[bytes, list[int]]:
|
||||
if entry.kind != 0:
|
||||
raise ValueError("Unexpected Steam shortcut record; no changes were made.")
|
||||
fields = entry.value
|
||||
title = fields.get("AppName", fields.get("appname"))
|
||||
path = fields.get("Exe", fields.get("exe"))
|
||||
if (title is not None and title.kind == 1 and title.value == NAME
|
||||
and path is not None and path.kind == 1 and path.value in (executable, f'"{executable}"')):
|
||||
# Ownership is the native executable, not the display title: Steam
|
||||
# lets users rename library entries, and the live client path treats
|
||||
# an entry pointing at the native executable as owned as well. Match
|
||||
# the path exactly, bare or quoted once, like the live client does.
|
||||
# A malformed app ID leaves the entry in place instead of aborting
|
||||
# the removal of the valid ones.
|
||||
if path is not None and path.kind == 1 and path.value in (executable, f'"{executable}"'):
|
||||
appid = fields.get("appid")
|
||||
if appid is None or appid.kind != 2 or not 2 ** 31 <= appid.value < 2 ** 32:
|
||||
raise ValueError("The native Halo shortcut has an invalid app ID; no changes were made.")
|
||||
continue
|
||||
matches.append(index)
|
||||
appids.append(appid.value)
|
||||
for index in matches:
|
||||
|
||||
@@ -124,6 +124,49 @@ def test_uninstall_keeps_saves_removes_all_exact_native_entries_and_managed_art(
|
||||
assert (saved / "save/profile.sav").read_bytes() == b"campaign progress"
|
||||
|
||||
|
||||
def test_uninstall_removes_a_native_entry_the_user_renamed(installation):
|
||||
remote, steam, configs, appids, _ = installation
|
||||
config = configs[0]
|
||||
executable = str(remote.GAME / "halo")
|
||||
root = steam.loads((config / "shortcuts.vdf").read_bytes())
|
||||
for entry in root["shortcuts"].value.values():
|
||||
path = entry.value.get("Exe")
|
||||
if path is not None and path.value in (executable, f'"{executable}"'):
|
||||
entry.value["AppName"] = steam.Value(1, "My favorite Halo")
|
||||
(config / "shortcuts.vdf").write_bytes(steam.dumps(root))
|
||||
result = remote.uninstall(RUN_ID, keep_saves=True)
|
||||
assert result["uninstalled"] and result["steam"]["status"] == "removed"
|
||||
assert result["steam"]["accounts"] == ["10", "20"]
|
||||
remaining = steam.loads((config / "shortcuts.vdf").read_bytes())["shortcuts"].value
|
||||
assert set(remaining) == {"0", "2"}
|
||||
assert "My favorite Halo" not in {entry.value["AppName"].value for entry in remaining.values()}
|
||||
assert result["steam"]["appids"] == sorted(set(appids))
|
||||
assert not (config / "grid" / f"{appids[0]}p.jpg").exists()
|
||||
assert not (config / "grid" / f"{appids[0]}.png").exists()
|
||||
assert (configs[1] / "grid" / f"{appids[1]}.png").read_bytes() == b"custom user tile"
|
||||
assert (configs[0] / "grid/10p.jpg").read_bytes() == b"other game's art"
|
||||
backups = list(config.glob("shortcuts.vdf.halo-frame-uninstall-*.bak"))
|
||||
assert len(backups) == 1 and b"My favorite Halo" in backups[0].read_bytes()
|
||||
|
||||
|
||||
def test_uninstall_skips_native_entries_with_malformed_ids_and_odd_quoting(installation):
|
||||
remote, steam, configs, _, _ = installation
|
||||
config = configs[0]
|
||||
executable = str(remote.GAME / "halo")
|
||||
root = steam.loads((config / "shortcuts.vdf").read_bytes())
|
||||
root["shortcuts"].value["3"] = steam.Value(0, OrderedDict([
|
||||
("appid", steam.Value(1, "not-a-number")), ("AppName", steam.Value(1, "Broken id")),
|
||||
("Exe", steam.Value(1, executable))]))
|
||||
root["shortcuts"].value["4"] = steam.Value(0, OrderedDict([
|
||||
("appid", steam.Value(2, 0xF2233445)), ("AppName", steam.Value(1, "Odd quotes")),
|
||||
("Exe", steam.Value(1, executable + '"'))]))
|
||||
(config / "shortcuts.vdf").write_bytes(steam.dumps(root))
|
||||
result = remote.uninstall(RUN_ID, keep_saves=True)
|
||||
assert result["uninstalled"] and result["steam"]["status"] == "removed"
|
||||
remaining = steam.loads((config / "shortcuts.vdf").read_bytes())["shortcuts"].value
|
||||
assert set(remaining) == {"0", "2", "3", "4"}
|
||||
|
||||
|
||||
def test_uninstall_without_keep_saves_deletes_contained_saves_only(installation):
|
||||
remote, _, _, _, _ = installation
|
||||
outside = remote.HOME / "external-saves"
|
||||
|
||||
Reference in new issue
Block a user