Compare commits

..

No commits in common. "5c07a77b63f8c21452f17ce4f6c2455b7ba554cd" and "bbaec35a5f21af56612224bf96df9bcf7c36691d" have entirely different histories.

8 changed files with 21 additions and 113 deletions

View File

@ -49,21 +49,9 @@ class Shortcuts:
def find_appname_by_unsigned_id(self, appid: int) -> str:
# NOTE: bitmask signed int back to 32-bit CRC
# varying client versions treat case sensitivity differently
try:
for key in self.shortcuts["shortcuts"].keys():
if self.shortcuts["shortcuts"][key]["appid"] & 0xFFFFFFFF == appid:
try:
return str(self.shortcuts["shortcuts"][key]["appname"])
except Exception as e:
logger.debug(e)
try:
return str(self.shortcuts["shortcuts"][key]["AppName"])
except Exception as e:
logger.debug(e)
return unknown
except Exception as e:
logger.debug(e)
return unknown
def get_shortcuts(self) -> Any:
@ -131,18 +119,22 @@ class Shortcuts:
https://developer.valvesoftware.com/wiki/Add_Non-Steam_Game
https://developer.valvesoftware.com/wiki/Steam_Library_Shortcuts
Key case is not internally consistent and varies between client versions
Most keys use Pascal case, but some do not
Wiki variously lists keys with title case and lowercase, but keys actually do
not seem to be case-sensitive. Some entries generated by Steam do not match the wiki
Keys are entered into the dictionary in a linear insertion order
# TODO: try to replicate key case sensitivity as it is created by Steam with generic shortcut
appid: signed int CRC
Exe: absolute path to the executable, must be wrapped in literal quotes
exe: absolute path to the executable, must be wrapped in literal quotes
StartDir: directory the executable starts in, generally the parent
"""
NEW_ENTRY: dict[str, Any] = {}
NEW_ENTRY["appid"] = meta.appid
NEW_ENTRY["AppName"] = meta.appname
NEW_ENTRY["Exe"] = f'"{meta.exe_path}"'
NEW_ENTRY["appname"] = meta.appname
NEW_ENTRY["exe"] = f'"{meta.exe_path}"'
NEW_ENTRY["StartDir"] = f"{meta.start_dir}"
NEW_ENTRY["icon"] = meta.icon
NEW_ENTRY["ShortcutPath"] = ""
@ -150,7 +142,7 @@ class Shortcuts:
NEW_ENTRY["IsHidden"] = 0
NEW_ENTRY["AllowDesktopConfig"] = 1
NEW_ENTRY["AllowOverlay"] = 1
NEW_ENTRY["OpenVR"] = 0
NEW_ENTRY["openvr"] = 0
NEW_ENTRY["Devkit"] = 0
NEW_ENTRY["DevkitGameID"] = ""
NEW_ENTRY["DevkitOverrideAppID"] = 0

View File

@ -205,28 +205,21 @@ def launch_offline(
proc = subprocess.run([*client_args, *params])
return proc.returncode
def find_loginusers(path: Path) -> Path:
return path / "config" / "loginusers.vdf"
def find_user_id(path: Path) -> str | None:
resolved_path = find_loginusers(path)
resolved_path = path / "config" / "loginusers.vdf"
try:
with open(resolved_path, "r") as f:
v = vdf.load(f)
# NOTE: beta client
# /package/beta
if len(v["users"]) == 1:
return str(list(v["users"].keys())[0])
for user in v["users"]:
if v["users"][user]["MostRecent"] == "1":
return str(user)
return None
except Exception as e:
logger.debug(e)
logger.warn(e)
return None
def find_user_id_32(path: Path) -> int:
uid = find_user_id(path)
if uid is None:

View File

@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
authors = [
{name = "aclist"}
]
version = "7.0.0b18"
version = "7.0.0b17"
license = "GPL-3.0-or-later"
license-files = ["LICENSE"]
readme = "README.md"

View File

@ -1,13 +0,0 @@
"users"
{
"0"
{
"AccountName" "STEAMUSER"
"PersonaName" "STEAMUSER"
"RememberPassword" "0"
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "0"
}
}

View File

@ -1,14 +0,0 @@
"users"
{
"0"
{
"AccountName" "STEAMUSER"
"PersonaName" "STEAMUSER"
"RememberPassword" "0"
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "1"
"Timestamp" "0"
}
}

View File

@ -1,25 +0,0 @@
"users"
{
"0"
{
"AccountName" "STEAMUSER"
"PersonaName" "STEAMUSER"
"RememberPassword" "0"
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "0"
"Timestamp" "0"
}
"1"
{
"AccountName" "STEAMUSER2"
"PersonaName" "STEAMUSER2"
"RememberPassword" "0"
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "1"
"Timestamp" "0"
}
}

View File

@ -1,25 +0,0 @@
import pytest
from pathlib import Path
from dzgui.api.steam import find_user_id
from tests.fixtures import fixture_path
pytestmark = pytest.mark.apitest
@pytest.mark.parametrize(
"fixture, expect",
[
("api/loginusers_legacy_client.vdf", 0),
("api/loginusers_legacy_client_multiple.vdf", 1),
("api/loginusers_beta_client.vdf", 0),
],
)
def test_loginusers(monkeypatch, fixture: str, expect: int) -> None:
def mock_loginusers(path: Path) -> Path:
return fixture_path(fixture)
monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers)
uid = find_user_id(Path(""))
assert int(uid) == expect

View File

@ -30,9 +30,9 @@ def test_no_shortcuts(monkeypatch) -> None:
@pytest.fixture
def dummy_app() -> None:
d = {
"AppName": "TEST APP",
"appname": "TEST APP",
"StartDir": "TEST_DIR",
"Exe": "TEST_DIR/TEST_EXE.EXE",
"exe": "TEST_DIR/TEST_EXE.EXE",
"icon": "IMAGES_DIR/TEST_IMAGE.PNG",
}
return d
@ -41,8 +41,8 @@ def dummy_app() -> None:
def test_wrap_exe(dummy_app) -> None:
s = Shortcuts(Path(""))
s.add_shortcut(*dummy_app.values())
assert s.shortcuts["shortcuts"]["0"]["Exe"][0] == '"'
assert s.shortcuts["shortcuts"]["0"]["Exe"][-1] == '"'
assert s.shortcuts["shortcuts"]["0"]["exe"][0] == '"'
assert s.shortcuts["shortcuts"]["0"]["exe"][-1] == '"'
def test_add_shortcut(dummy_app) -> None:
@ -51,7 +51,7 @@ def test_add_shortcut(dummy_app) -> None:
new = s.shortcuts["shortcuts"]
ind = str(len(new) - 1)
for k, v in dummy_app.items():
if k == "Exe":
if k == "exe":
v = f'"{v}"'
assert new[ind][k] == v