List named Remote Play hosts in redesigned localized launch chooser

This commit is contained in:
toorux committed 2026-10-07 14:32:50 +08:00
1 parent e8c406ffca
commit 6589f85ec6
10 files changed
+112 -20

No files matched your search

+30 -9
View File
@@ -13,12 +13,18 @@ pub struct App {
pub remote: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub remote_client: Option<String>,
pub remote_targets: Vec<RemoteTarget>,
pub id: u32,
pub name: String,
pub kind: &'static str,
pub icon: Option<String>,
pub icon_fit: &'static str,
}
#[derive(Clone, Debug, Serialize)]
pub struct RemoteTarget {
pub client: String,
pub name: String,
}
#[derive(Debug)]
enum Value {
Text(String),
@@ -213,6 +219,7 @@ pub fn discover(home: &Path) -> Vec<App> {
id,
remote: false,
remote_client: None,
remote_targets: Vec::new(),
name: name.into(),
kind: if text(v, "installdir").is_some_and(|dir| {
fs::read_dir(library.join("steamapps/common").join(dir)).is_ok_and(
@@ -320,14 +327,7 @@ fn merge_remote(home: &Path, local: Vec<App>, remote: Vec<remote::RemoteApp>) ->
home.join(".steam/steam")
};
for a in remote {
if let Some(existing) = apps.get_mut(&a.id) {
// Keep local metadata and a single stable icon, but expose both launch targets.
if existing.remote_client.is_none() {
existing.remote_client = Some(a.client);
}
continue;
}
apps.entry(a.id).or_insert_with(|| {
let existing = apps.entry(a.id).or_insert_with(|| {
let icon = cached_artwork(&steam, a.id);
App {
id: a.id,
@@ -336,9 +336,23 @@ fn merge_remote(home: &Path, local: Vec<App>, remote: Vec<remote::RemoteApp>) ->
icon_fit: icon.as_ref().map(|v| v.1).unwrap_or("contain"),
icon: icon.map(|v| v.0),
remote: true,
remote_client: Some(a.client),
remote_client: None,
remote_targets: Vec::new(),
}
});
if existing.remote_targets.iter().any(|t| t.client == a.client) {
continue;
}
if existing.remote_client.is_none() {
existing.remote_client = Some(a.client.clone());
}
existing.remote_targets.push(RemoteTarget {
client: a.client,
name: a.device_name,
});
existing
.remote_targets
.sort_by(|a, b| a.name.cmp(&b.name).then(a.client.cmp(&b.client)));
}
apps.into_values().collect()
}
@@ -383,22 +397,26 @@ mod tests {
icon_fit: "contain",
remote: false,
remote_client: None,
remote_targets: Vec::new(),
}];
let rows = vec![
remote::RemoteApp {
id: 42,
name: "Same remote".into(),
client: "12".into(),
device_name: "Gaming PC".into(),
},
remote::RemoteApp {
id: 43,
name: "Remote".into(),
client: "12".into(),
device_name: "Gaming PC".into(),
},
remote::RemoteApp {
id: 43,
name: "Other host".into(),
client: "13".into(),
device_name: "Laptop".into(),
},
];
let apps = merge_remote(home.path(), local, rows);
@@ -406,6 +424,9 @@ mod tests {
assert!(!apps[0].remote);
assert_eq!(apps[0].name, "Local");
assert_eq!(apps[0].remote_client.as_deref(), Some("12"));
assert_eq!(apps[0].remote_targets[0].name, "Gaming PC");
assert_eq!(apps[1].remote_targets.len(), 2);
assert_eq!(apps[1].remote_targets[1].name, "Laptop");
assert!(apps[1].remote);
assert_eq!(apps[1].remote_client.as_deref(), Some("12"));
}
+2 -2
View File
@@ -4,14 +4,14 @@ async function(request) {
if(request.mode==='list')return [];
throw Error('Steam remote library is unavailable');
}
const connected=new Set(remote.devices.filter(d=>d.status==='Connected').map(d=>String(d.clientId)));
const connected=new Map(remote.devices.filter(d=>d.status==='Connected').map(d=>[String(d.clientId),String(d.clientName||'').trim().slice(0,256)]));
const rows=[];
for(const a of store.allApps) {
if(!Number.isInteger(a.appid)||a.appid<=0||a.appid>4294967295||a.visible_in_game_list===false||!(a.app_type&(1|2|8)))continue;
for(const r of a.remote_per_client_data||[]) {
const client=String(r.clientid);
if(r.installed===true&&/^\d{1,20}$/.test(client)&&connected.has(client)&&a.BIsPerClientDataLocal?.(r)===false)
rows.push({id:a.appid,name:String(a.display_name||''),client});
rows.push({id:a.appid,name:String(a.display_name||''),client,deviceName:connected.get(client)});
}
}
if(request.mode==='list')return rows.slice(0,10000);
+2
View File
@@ -11,6 +11,8 @@ pub(super) struct RemoteApp {
pub id: u32,
pub name: String,
pub client: String,
#[serde(default, rename = "deviceName")]
pub device_name: String,
}
fn query(request: serde_json::Value) -> Result<serde_json::Value> {
crate::apk::steam_ui::evaluate(&format!("({})({request})", include_str!("remote.js")))