feat(host/windows): Steam library auto-discovery on Windows
apple / swift (push) Successful in 53s
android / android (push) Failing after 44s
ci / web (push) Successful in 40s
ci / docs-site (push) Successful in 32s
ci / rust (push) Failing after 2m28s
decky / build-publish (push) Successful in 44s
ci / bench (push) Failing after 1m22s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
flatpak / build-publish (push) Failing after 2s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 37s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 45s
deb / build-publish (push) Failing after 2m46s
docker / deploy-docs (push) Successful in 10s
apple / swift (push) Successful in 53s
android / android (push) Failing after 44s
ci / web (push) Successful in 40s
ci / docs-site (push) Successful in 32s
ci / rust (push) Failing after 2m28s
decky / build-publish (push) Successful in 44s
ci / bench (push) Failing after 1m22s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
flatpak / build-publish (push) Failing after 2s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 37s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 45s
deb / build-publish (push) Failing after 2m46s
docker / deploy-docs (push) Successful in 10s
The Steam `LibraryProvider` keyed off `$HOME` + Linux paths, so the game library was empty on Windows. Add Windows discovery: the default Steam install dirs under Program Files (`ProgramFiles(x86)`/`ProgramFiles`/ `ProgramW6432`), with games on other drives picked up via each root's `libraryfolders.vdf` — whose Windows values are backslash-escaped, so unescape `\\` → `\`. The existing root-scan/dedup logic is shared via a new `steam_roots_existing` helper. The custom store (mgmt JSON CRUD) was already cross-platform; only Steam auto-discovery was Linux-only. Not yet covered: a non-default Steam install dir (the registry `Valve\Steam\InstallPath`). Degrades gracefully — no Steam → empty list. clippy -D warnings + library tests green on Windows and Linux. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -127,6 +127,7 @@ fn steam_art(appid: u32) -> Artwork {
|
||||
}
|
||||
|
||||
/// Candidate Steam roots (classic, Flatpak, Deck) that actually exist, canonicalized + deduped.
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn steam_roots() -> Vec<PathBuf> {
|
||||
let Some(home) = std::env::var_os("HOME").map(PathBuf::from) else {
|
||||
return Vec::new();
|
||||
@@ -137,6 +138,25 @@ fn steam_roots() -> Vec<PathBuf> {
|
||||
home.join(".steam/root"),
|
||||
home.join(".var/app/com.valvesoftware.Steam/.local/share/Steam"), // Flatpak Steam
|
||||
];
|
||||
steam_roots_existing(candidates)
|
||||
}
|
||||
|
||||
/// Windows Steam roots: the default install dirs under Program Files. Games installed on other
|
||||
/// drives are still found via each root's `libraryfolders.vdf` (see [`steam_library_dirs`]). A
|
||||
/// non-default Steam install dir (registry `Valve\Steam\InstallPath`) isn't covered yet.
|
||||
#[cfg(target_os = "windows")]
|
||||
fn steam_roots() -> Vec<PathBuf> {
|
||||
let mut candidates = Vec::new();
|
||||
for var in ["ProgramFiles(x86)", "ProgramFiles", "ProgramW6432"] {
|
||||
if let Some(pf) = std::env::var_os(var) {
|
||||
candidates.push(PathBuf::from(pf).join("Steam"));
|
||||
}
|
||||
}
|
||||
steam_roots_existing(candidates)
|
||||
}
|
||||
|
||||
/// Keep only the candidate roots that exist (have a `steamapps` dir), canonicalized + deduped.
|
||||
fn steam_roots_existing(candidates: impl IntoIterator<Item = PathBuf>) -> Vec<PathBuf> {
|
||||
let mut seen = HashSet::new();
|
||||
let mut roots = Vec::new();
|
||||
for c in candidates {
|
||||
@@ -174,12 +194,21 @@ fn steam_library_dirs() -> Vec<PathBuf> {
|
||||
}
|
||||
|
||||
/// Pull every `"path" "<dir>"` value out of a `libraryfolders.vdf`. We don't need a full VDF
|
||||
/// parser for the two flat fields we read — Linux library paths never contain the `"` or `\`
|
||||
/// that would require unescaping.
|
||||
/// parser for the two flat fields we read. On Windows the values are backslash-escaped
|
||||
/// (`D:\\SteamLibrary`), so unescape `\\` → `\`; Linux paths need no unescaping.
|
||||
fn vdf_paths(text: &str) -> Vec<String> {
|
||||
text.lines()
|
||||
.filter_map(|l| vdf_value(l.trim(), "path"))
|
||||
.map(str::to_string)
|
||||
.map(|p| {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
p.replace("\\\\", "\\")
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
p.to_string()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user